Přidělení paměti založené na zásobníku - Stack-based memory allocation
Zásobníky ve výpočetních architekturách jsou oblasti paměti, kde jsou data přidávána nebo odebírána způsobem LIFO (last-in-first-out) .
Ve většině moderních počítačových systémů má každé vlákno vyhrazenou oblast paměti označovanou jako jeho zásobník. Když se funkce spustí, může přidat některá ze svých místních stavových dat na začátek zásobníku; když funkce skončí, je zodpovědná za odebrání těchto dat ze zásobníku. Minimálně se zásobník podprocesu používá k uložení umístění zpáteční adresy poskytnuté volajícím, aby bylo možné návratovým příkazům vrátit se na správné místo. Zásobník se často používá k ukládání proměnných pevné délky lokálně k aktuálně aktivním funkcím. Programátoři se dále mohou rozhodnout výslovně použít zásobník k ukládání lokálních dat proměnné délky. Pokud oblast paměti leží na zásobníku podprocesu, říká se, že tato paměť byla alokována v zásobníku, tj . Přidělení paměti založené na zásobníku .
Výhody a nevýhody
Protože jsou data přidávána a odebírána způsobem poslední v pořadí, je přidělování paměti založené na zásobníku velmi jednoduché a obvykle mnohem rychlejší než přidělování paměti založené na haldě (známé také jako dynamické přidělování paměti ) obvykle přidělované prostřednictvím malloc. Další funkcí je, že paměť v zásobníku se automaticky a velmi efektivně obnovuje po ukončení funkce, což může být výhodné pro programátora, pokud již data nejsou požadována. (Totéž platí pro longjmp, pokud se přesunul do bodu před voláním, které se alloca
stalo.) Pokud je však třeba data uchovávat v nějaké formě, musí být před ukončením funkce zkopírována ze zásobníku na hromadu. Alokace založená na zásobníku je proto vhodná pro dočasná data nebo data, která již po ukončení aktuální funkce nejsou nutná.
Velikost zásobníku přiřazená vláknu může být na některých malých CPU tak malá, jako jen několik bajtů. Přidělení většího množství paměti v zásobníku, než je k dispozici, může mít za následek selhání kvůli přetečení zásobníku . To je také důvod, proč alloca
je obvykle zabráněno vložení funkcí, které používají : pokud by byla taková funkce vložena do smyčky, volající by trpěl neočekávaným nárůstem využití zásobníku, což by přetečení znamenalo mnohem větší pravděpodobnost.
Alokace založená na zásobníku může také způsobit menší problémy s výkonem: vede k rámcům zásobníku proměnné velikosti, takže je třeba spravovat ukazatele zásobníku i rámce (u rámců zásobníku pevné velikosti je jeden z nich nadbytečný). To je obvykle mnohem méně nákladné než volání malloc
a free
stejně. Zejména pokud aktuální funkce obsahuje jak volání aloky, tak bloky obsahující lokální data s proměnnou délkou, pak dochází ke konfliktu mezi pokusy aloky o zvýšení aktuálního rámce zásobníku, dokud aktuální funkce neskončí oproti potřebě kompilátoru umístit lokální proměnné proměnné délky do stejné umístění v rámečku zásobníku. Tento konflikt je obvykle vyřešen vytvořením samostatného řetězce haldy úložiště pro každé volání alokace (viz: https://code.woboq.org/gcc/libiberty/alloca.c.html ). Řetězec zaznamenává hloubku zásobníku, při které dochází k každé alokaci, následné volání alokace v jakékoli funkci ořízne tento řetězec až na aktuální hloubku zásobníku, aby nakonec (ale ne hned) uvolnilo jakékoli úložiště v tomto řetězci. Volání alokace s nulovým argumentem lze také použít ke spuštění uvolnění paměti bez přidělení další takové paměti. V důsledku tohoto konfliktu mezi alokou a lokálním úložištěm proměnných nemusí být používání aloky o nic efektivnější než používání malloc.
Rozhraní systému
Mnoho unixových systémů a Microsoft Windows implementují funkci, která vyžaduje alloca
dynamické přidělování paměti zásobníku podobným způsobem jako na základě haldy malloc
. Kompilátor jej obvykle převede na vložené pokyny manipulující s ukazatelem zásobníku, podobně jako se zachází s poli s proměnnou délkou . Přestože není nutné paměť výslovně uvolňovat, existuje riziko nedefinovaného chování kvůli přetečení zásobníku. Tato funkce byla na unixových systémech přítomna již v 32/V (1978), ale není součástí standardu C ani standardu POSIX .
V systému Microsoft Windows existuje bezpečnější verze alloca
volání _malloca
, která hlásí chyby. Vyžaduje použití _freea
. gnulib poskytuje ekvivalentní rozhraní, i když místo vyvolání výjimky SEH při přetečení deleguje, malloc
když je detekována nadměrná velikost. Podobnou funkci lze emulovat pomocí ručního účetnictví a kontroly velikosti, například při použití alloca_account
v glibc.
Některé rodiny procesorů, například x86 , mají speciální pokyny pro manipulaci se zásobníkem aktuálně prováděného vlákna. Jiné rodiny procesorů, včetně PowerPC a MIPS , nemají explicitní podporu zásobníku, ale místo toho se spoléhají na konvenci a delegují správu zásobníku na binární rozhraní aplikace (ABI) operačního systému .
Viz také
- Automatická proměnná
- Statická proměnná
- Zásobník hovorů
- Dynamické přidělování paměti
- Přetečení vyrovnávací paměti zásobníku
- Stohovací stroj
- Přetečení zásobníku