Stack Overflow

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 17 maj 2021; kontroller kräver 4 redigeringar .

I mjukvara uppstår ett stackspill när det finns mer information lagrad på samtalsstacken än den kan hålla. Vanligtvis ställs stackkapaciteten vid program-/trådstart. När stackpekaren går utanför gränserna kraschar programmet. [ett] 

Detta fel uppstår av tre anledningar. [2]

Oändlig rekursion

Det enklaste exemplet på oändlig rekursion i C :

int foo () { return foo (); }

Funktionen anropar sig själv och tar utrymme på stacken tills stacken svämmar över och ett segmenteringsfel uppstår . [3]

Detta är ett förfinat exempel, och i verklig kod kan oändlig rekursion uppträda av två anledningar:

Rekursionsutgångsvillkor misslyckades

En vanlig orsak till oändlig rekursion är när, under vissa extrema oprövade omständigheter, rekursionsavbrottsvillkoret inte fungerar alls.

int factorial ( int n ) { om ( n == 0 ) retur 1 ; returnera n * faktoriell ( n - 1 ); }

Programmet kommer att gå in i djup (4 miljarder samtal) rekursion om n är negativ .

Många språk gör en optimering som kallas " svansrekursion ". Rekursionen i slutet av funktionen förvandlas till en loop och förbrukar inte stacken [4] . Om en sådan optimering fungerar blir det en loop istället för en stack overflow .

Programmeraren skrev indirekt rekursion utan att inse det

En programmerare kan skriva rekursion oavsiktligt, till exempel när flera överbelastade funktioner utför samma funktionalitet, och en anropar en annan.

int Obj::getData ( int index , bool & isChangeable ) { isChangeable = sant ; return getData ( index ); } int Obj::getData ( int index ) { bool noMatter ; return getData ( index , noMatter ); }

Se även Ond cirkel , Sepulki .

I gränssnittsramverk som Qt och VCL kan rekursion inträffa om till exempel en fältändringshanterare ändrar själva fältet.

Mycket djup rekursion

Du kan förstöra en enskilt länkad lista med följande kod:

void destroyList ( struct Item * it ) { if ( it == NULL ) återvända ; destroyList ( it -> nästa ); gratis ( it ); }

Denna algoritm, om listan inte är skadad, kommer teoretiskt att köras i ändlig tid, vilket kräver O( n ) i stacken. Naturligtvis, med en lång lista kommer programmet att misslyckas. Möjliga lösningar:

  • Hitta en icke-rekursiv algoritm (fungerar i det här exemplet).
  • Flytta rekursion från hårdvarustacken till en dynamiskt allokerad (till exempel när du kringgår olika typer av nätverk [5] ).
  • Om rekursionen har gått djupt, använd en annan metod. Quicksort är till exempel en extremt effektiv sorteringsmetod  som kan använda mycket stackutrymme i extrema fall. Därför begränsar sorteringsimplementeringar i programmeringsspråk djupet av rekursion, och om de når gränsen använder de långsammare metoder som pyramidal sortering . Så fungerar till exempel Introsort .

Stora variabler på stacken

Den tredje stora anledningen till stackoverflows är engångsallokeringen av enorma mängder minne av stora lokala variabler. Många författare rekommenderar att allokera minne som är större än några kilobyte på " högen " snarare än på högen. [6]

Exempel i C :

int foo () { dubbel x [ 1000000 ]; }

Arrayen upptar 8 megabyte minne; om det inte finns tillräckligt med minne i stacken kommer ett spill att inträffa.

Allt som minskar den effektiva stackstorleken ökar risken för översvämning. Trådar tar vanligtvis mindre stack än huvudprogrammet - så programmet kan fungera i enkeltrådsläge och misslyckas i flertrådsläge. Subrutiner som körs i kärnläge använder ofta någon annans stack, så när de programmerar i kärnläge försöker de att inte använda rekursion och stora lokala variabler. [7] [8]

Se även

Anteckningar

  1. Burley, James Craig Använder och porterar GNU Fortran (länk ej tillgänglig) (1 juni 1991). Hämtad 30 mars 2012. Arkiverad från originalet 5 oktober 2012. 
  2. Danny, Kalev Understanding Stack Overflow (5 september 2000). Hämtad 30 mars 2012. Arkiverad från originalet 27 september 2020.
  3. Vad är skillnaden mellan ett segmenteringsfel och ett stackspill? Arkiverad 9 mars 2012 på Wayback Machine på StackOverflow
  4. En introduktion till schemat och dess genomförande (nedlänk) (19 februari 1997). Hämtad 30 mars 2012. Arkiverad från originalet 23 augusti 2000. 
  5. Ett exempel på en bugg Arkiverad 13 november 2020 på Wayback Machine i poly2tri , ett välkänt bibliotek för att konstruera en begränsad Delaunay-triangulering av en polygon; buggen fixades av STL dynamiska stacken .
  6. Feldman, Howard Modern Memory Management, del 2 (23 november 2005). Hämtad 30 mars 2012. Arkiverad från originalet 5 oktober 2012.
  7. Kärnprogrammeringsguide: Prestanda- och stabilitetstips . Apple Inc. (7 november 2006). Hämtad 30 september 2017. Arkiverad från originalet 7 december 2008.
  8. Dunlap, Randy Linux Kernel Development: Komma igång (nedlänk) (19 maj 2005). Hämtad 30 mars 2012. Arkiverad från originalet 5 oktober 2012.