Prostota C
Język C, z założenia skupiający się na prostocie w swej budowie obarcza programistę sporą ilością pracy i koniecznością dbania o detale, o których istnieniu możemy zapomnieć pisząc w nowocześniejszych językach.
Takie podejście pozwala lepiej zrozumieć maszyny i ich tendencję do bycia głupim, niewykwalifikowanym, choć dokładnym pracownikiem. O ile pozwala to, na lepsze wykorzystanie zasobów maszyny i dokładniejszą optymalizację, to trudno nazwać to zadanie wygodnym.
Kolekcjonowanie odpadków
Programiści języków takich jak C#, Java czy Python o alokację i zwalnianie pamięci troszczyć się nie muszą — tym zadaniem obarczone jest środowisko uruchomieniowe, które dba o sprzątanie całego bajzlu który zostawił po sobie programista, dlaczego więc nie wykorzystać podobnego mechanizmu w C? Z pomocą przychodzi biblioteka GC.
GC udostępnia nam pięć funkcji (makr):
- GC_INIT() — inicjalizuje bibliotekę
- GC_MALLOC_ATOMIC() — odpowiednik malloc()
- GC_MALLOC() — odpowiednik calloc()
- GC_REALLOC() — odpowiednik realloc()
- GC_FREE() — odpowiednik free(), w większości przypadków całkowicie zbędny.
Ich definicje znajdziemy w pliku gc.h.
Przykład wykorzystania GC
Zbudujmy więc prosty program operujący na nich. Dla wygody przykryjemy standardowe funkcje C ich odpowiednikami z biblioteki GC.
|
|
Kompilacja i jej efekty
Oczywiście “hello world” wcale nie musi używać dynamicznie alokowanej pamięci, jednak jest przykładem wystarczającym do zobrazowania sytuacji. Wywołanie GC_INIT() na Linuksach jest opcjonalne. Kompilacja odbywa się poprzez wywołanie clang -pedantic -lgc -o hello hello.c. Nic nadzwyczajnego, wykonanie programu też nie jest jakąś zagadką. Jednak warto zerknąć na dokumentację GC, a konkretniej README.environment. Po zdefiniowaniu zmiennej środowiskowej GC_PRINT_STATS program podczas działania będzie wyświetlał na standardowe wyjście statystyki alokacji i zwalniania pamięci. Jak widać, używanie free() stało się zbędne.
Wnioski?
O ile w tak prostym przykładzie ręczne zwalnianie pamięci nie jest problemem, to już przy dłuższym kodzie automatyzacja staje się bardzo wygodnym narzędziem, a także rozwiązuje problematykę alokowania pamięci wewnątrz funkcji która zwraca wskaźnik na tę pamięć. Czasem późniejsze zwolnienie jej jest utrudnione przez wymogi reszty kodu, a programista może zwyczajnie zapomnieć o wywołaniu free(). Dzięki bibliotece GC możesz zapomnieć o wyciekach pamięci, a samo działanie Garbage Collectora nie jest aż tak obciążające dla współczesnego sprzętu, by rezygnować z niego w imię optymalizacji.