‟overcq”

Z bloga o OUX/C+

Menedżer bloków pamięci — “mem-blk.cx”

W języku C+ na stosie programowym przechowuje się tylko dane o małym rozmiarze, znanym w czasie kompilacji, takie jak adresy powrotu z procedur (przechowywane automatycznie) oraz małe zmienne lokalne. Wszystkie pozostałe dane należy przechowywać na stercie programowej, czyli w pamięci dodatkowej, która jest obsługiwana przez menedżera bloków. Zarządza on obiektami “blk” przynależącymi do modułu języka C+ “mem”.

Podstawowe procedury tego menedżera zostały opisane w tym wpisie, o instrukcjach wbudowanych, pod nagłówkiem “Zarządzanie pamięcią”. Są to procedury przydzielenia i zwolnienia pamięci czyli utworzenia i wyrzucenia obiektu “E_mem_Q_blk”. Natomiast jeśli ma się ten obiekt, to można zmieniać jego rozmiar, a nawet podzielić go na dwa obiekty.

Menedżer bloków przydziela pamięć o podanym rozmiarze bloku, natomiast liczba bloków może być równa 0. W wyniku przydzielenia bloku lub bloków pamięci otrzymujemy adres początku pierwszego bloku, a w przypadku żądania zerowej liczby bloków – symboliczną liczbę identyfikującą pusty blok. Jeśli przydzielenie pamięci się nie powiedzie, to otrzymujemy 0. Instrukcje wbudowane “M” i “M_” przydzielają podaną liczbę bloków o rozmiarze 1 bajta czyli dokładnie tyle bajtów pamięci, ile podano.

Bloki przydzielonej pamięci są umieszczone pod adresami wyrównanymi do potęgi dwójki, jeśli zażądano rozmiar będący potęgą dwójki, ale tylko do rozmiaru liczby N.

Zmiana liczby przydzielonych bloków

Mamy do dyspozycji następujące procedury zwiększenia liczby przydzielonych bloków pamięci, w zależności od tego, w którym miejscu wymagane jest dodanie pamięci. Procedury te biorą wskaźnik do zmiennej przechowującej adres bloku i uaktualniają go, więc należy pamiętać, by pomiędzy wywołaniami tych procedur nie przechowywać innych wskaźników do bloku pamięci, ale na przykład przesunięcia od początku bloku.

P
E_mem_Q_blk_I_add( P p
, N n
, N *n_prepended
, N *n_appended
);

Dodaje pamięć na końcu lub na początku bloku, w zależności od tego, gdzie znajdzie wolne miejsce.

P
E_mem_Q_blk_I_append( P p
, N n
);
P
E_mem_Q_blk_I_prepend( P p
, N n
);

Dodają odpowiednio: na końcu bloku lub na początku.

P
E_mem_Q_blk_I_insert( P p
, N i
, N n
);

Wstawia podaną liczbę bloków przed blokiem o podanym numerze.

Mamy do dyspozycji następującą procedurę zmniejszenia liczby przydzielonych bloków:

P
E_mem_Q_blk_I_remove( P p
, N i
, N n
);

Usuwa ona podaną liczbę bloków począwszy od bloku o podanym numerze.

I ostatecznie mamy do dyspozycji następującą procedurę podziału bloków na dwie części:

P
E_mem_Q_blk_M_split( P p
, N i
);

Zabiera ona z podanego adresu bloki począwszy od bloku o podanym numerze i tworzy z nich nowy adres do zarządzania blokami, który podaje i który trzeba osobno wyrzucić. Procedura ta nie bierze wskaźnika, lecz bezpośrednio adres pamięci.

Procedury narzędziowe

P
E_mem_Q_blk_I_copy( P dst
, P src
, N l
);
P
E_mem_Q_blk_I_copy_rev( P dst
, P src
, N l
);
P
E_mem_Q_blk_I_copy_auto( P dst
, P src
, N l
);

Procedury te kopiują pamięć o podanym rozmiarze: od początku do końca, od końca do początku albo automatycznie wybierają kierunek.

Procedury zastępujące menedżera systemu systemu operacyjnego

Jeśli włączone jest zastępowanie procedur przydzielania pamięci systemu operacyjnego w programie, to następujące procedury zostaną skompilowane i podstawione, pod warunkiem wczesnego dołączenia modułu podsystemu OUX “base” do programu, na przykład ustawiwszy zmienną środowiska “sh” “LD_PRELOAD=liboux-base.so”.

P
malloc( size_t l
);
P
calloc( size_t n
, size_t u
);
P
realloc( P p
, size_t l
);
void
free( P p
);
int
posix_memalign( P *p
, size_t align
, size_t size
);
size_t
malloc_usable_size( P p
);

Jeśli brak parametru, to bloki przydzielone tymi procedurami są wyrównane do rozmiaru “2 * N”.