piątek, 30 października 2015

valgrind - szukanie wycieków pamięci

Chciałbym zaprezentować pożyteczny program konsolowy valgrind, który bada wycieki pamięci w programach.

Wyciek pamięci (ang. memory leak) – niezamierzone użycie pamięci przez program komputerowy, gdy nie zwalnia on zaalokowanej wcześniej pamięci, która nie jest już mu potrzebna.

Wycieki pamięci są efektem bardzo niepożądanym. Program bowiem zajmuje coraz więcej pamięci, ale nie jest w stanie jej wykorzystać ani zwolnić. Szczególnie w aplikacjach, które działają przez długi czas (w większości serwerowych), efekt wycieku pamięci stopniowo narasta. Sam wyciek prowadzi do spadku wydajności systemu, w skrajnym przypadku zawieszenia się programu lub innych programów, którym system nie może przydzielić wystarczającej ilości pamięci, a nawet zablokowania całego systemu operacyjnego. Kod programu, który powoduje wycieki pamięci, jest kodem błędnym.

Użycie programu valgrind jest bardzo proste:

valgrind nazwa_programu

np.:

valgrind putty
valgrind ./myprog

Wynikiem powyższych poleceń jest uruchomienie danego programu, a po jego zakończeniu wyświetlenie ilości bajtów, które wyciekły.

Program valgrind przydaje się, gdy na komputerze uruchamiamy program, który po pewnym czasie zaczyna "mulić". Można wtedy sprawdzić, czy nie ma dużych wycieków pamięci.

W językach programowania takich jak Java czy C# problem wycieków pamięci został częściowo zniwelowany poprzez zastosowanie odśmiecania pamięci (ang. Garbage Collector). W językach C i C++ programista musi zwalniać pamięć. Poniżej przykład programu w C, który nie zwalnia zaalokowanej wcześniej pamięci na zmienną typu int (4 bajty):

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
  int *x = malloc(sizeof(int));
  *x = 16;
  printf("%d\n",*x);
  return 0;
}

Powyższy kod kompilujemy następująco:

gcc memleak.c -o memleak

Sprawdzamy wycieki pamięci:

valgrind ./memleak

Dostajemy informację, że wyciekły 4 bajty.

Poprawnie napisany program powinien zawierać funkcję free(), która zwalnia zarezerwowaną wcześniej pamięć:
 
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
  int *x = malloc(sizeof(int));
  *x = 16;
  printf("%d\n",*x);
  free(x);
  return 0;
}