Přetečení zásobníku
V oblasti výpočetní techniky dochází k přetečení zásobníku , když je na zásobníku vyžadováno příliš mnoho paměti .
V mnoha programovacích jazycích obsahuje zásobník volání omezené množství paměti, které je obvykle opraveno při spuštění programu. Velikost zásobníku závisí na mnoha faktorech, včetně programovacího jazyka, architektury stroje, použití multithreadingu a dostupnosti paměti v systému. Když je v zásobníku použito příliš mnoho paměti , říká se, že dojde k přetečení a dojde k pádu programu [1] . Tato třída chyb je obvykle způsobena jedním ze dvou typů programovacích chyb [2] : nekonečná rekurze a použití velmi velkých proměnných zásobníku.
Nekonečná rekurze
Nejčastější příčinou přetečení zásobníku je rekurze s nadměrnou nebo nekonečnou hloubkou.
Jazyky, které implementují techniku tail rekurze , jako je jazyk Scheme , umožňují konkrétní nekonečnou rekurzi, kterou lze provádět bez přetečení zásobníku. Je to proto, že volání využívající tail-recursion nevyžadují další zásobník [3] .
Velmi velké proměnné zásobníku
Další hlavní příčinou přetečení zásobníku je pokus o přidělení více paměti, než je v zásobníku k dispozici. To se stane, když vytvoříte velmi velké pole lokálních proměnných . Z tohoto důvodu by pole větší než několik kilobajtů měla být alokována dynamicky , spíše než je alokovat jako lokální proměnné [4] .
Příčiny, které mohou snížit dostupnou velikost zásobníku a tím zvýšit pravděpodobnost přetečení zásobníku
Přetečení zásobníku je spojeno se vším, co snižuje efektivní velikost zásobníku programu .
Například program spuštěný jako jedno vlákno může fungovat správně, ale pokud stejný program běží s více vlákny, dojde k selhání programu , protože mnoho programů, které používají vlákna, má pro každé vlákno k dispozici menší zásobník než program. nepoužívá vlákna.
Podobně těm, kteří studují vývoj jádra , se doporučuje nepoužívat rekurzivní algoritmy a velmi velké vyrovnávací paměti v zásobníku [5] [6] .
Příklady v jazyce C / C ++
Nekonečná rekurze s jednou funkcí
void f () {
f ();
}
int main ( void ) {
f ();
návrat 0 ;
}
Tento úryvek kódu volá funkci f() a ta f()zase volá sama sebe, čímž generuje nekonečnou rekurzi.
Nekonečná rekurze se dvěma funkcemi
void f ( void ); void g ( void );
int main ( void ) {
f ();
návrat 0 ;
}
void f ( void ) {
g ();
}
void g ( void ) {
f (); }
Funkce f()a funkce se g()navzájem volají nepřetržitě, dokud nedojde k přetečení zásobníku.
Proměnná v zásobníku je příliš velká
int main ( void ) {
dvojité n [ 10000000 ]; návrat 0 ;
}
Pole deklarované v tomto fragmentu kódu vyžaduje více paměti, než je dostupné v zásobníku, což způsobuje přetečení zásobníku.
Poznámky
- ^ James Craig Burley, Používání a portování GNU Fortran , na sunsite.ualberta.ca , 1. června 1991 (archivováno z originálu 5. října 2012) .
- ^ Kalev Danny, Understanding Stack Overflow , devx.com , 5. září 2000.
- ^ An Introduction to Scheme and its Implementation , na federated.com , 19. února 1997 (z originálu archivováno 10. srpna 2007) .
- ^ Howard Feldman, Modern Memory Management, Part 2 , onlamp.com , 23. listopadu 2005. Získáno 10. listopadu 2009 (z originálu archivováno 20. září 2012) .
- ^ Průvodce programováním jádra: Tipy pro výkon a stabilitu , na adrese developer.apple.com , Apple Inc. , 7. listopadu 2006 (z originálu archivováno 7. prosince 2008) .
- ^ Randy Dunlap, Linux Kernel Development: Getting Started ( PDF ), na xenotime.net , 19. května 2005 (z originálu archivováno 27. února 2012) .