2009-10-17 5 views
6

Senza utilizzare la ricorsione come può essere generata un'eccezione di overflow dello stack?Senza utilizzare la ricorsione come può essere generata un'eccezione di overflow dello stack?

+0

Ci scusiamo per il corpo domanda ripetitiva, ma non riuscivo a pensare a nulla vale la pena di aggiungere. – JaredCacurak

+0

Va bene. Spesso mi trovavo nella stessa posizione :) – pierrotlefou

+0

Puoi sempre inserire nt (senza testo) nel corpo. Ha sempre funzionato nei giorni BBS. Lo stackoverflow –

risposta

12

Se si richiamano metodi sufficienti, un overflow dello stack può verificarsi in qualsiasi momento. Sebbene, se si ottengono errori di overflow dello stack senza ricorrere alla ricorsione, è possibile che si desideri riconsiderare il modo in cui si eseguono le operazioni. È così facile con la ricorsione perché in un ciclo infinito, si chiama un sacco di metodi.

16

Dichiarare un array ENORMOUS come variabile locale.

+0

La maggior parte dei compilatori semplicemente non li compila. Questo non è un eccesso di stack. –

+1

@Chris - Non lo compilerà? Ho pensato che la dimensione massima dello stack fosse impostata dal linker e non fosse nota al compilatore. – ChrisW

+2

il compilatore non può prenderlo, a meno che il compilatore non sia in grado di analizzare il codice per l'utilizzo previsto dello stack in fase di esecuzione, il che potrebbe essere estremamente complicato. – JustJeff

2

Ogni chiamata di metodo che non è stata ancora restituita consuma dello spazio di stack. (I metodi con più variabili locali consumano più spazio.) Uno stack di chiamate molto profondo può causare un overflow dello stack.

Si noti che su sistemi con memoria limitata (dispositivi mobili e così via) non si dispone di molto spazio nello stack e si esaurirà prima.

+1

Ho lavorato su un progetto di console in cui i nostri processi avevano stack 32K. In una delle routine, c'erano due array 16K. Sebbene l'uso degli array fosse esclusivo e non fossero nello stesso ambito, il compilatore assegnava ancora 32K di spazio nello stack e traboccava il nostro stack (in teoria un compilatore più intelligente avrebbe riservato solo 16K). Li ho modificati entrambi per allocare/liberare per risolvere il problema. – Adisak

20

Dal momento che nessuno altro ha parlato:

throw new System.StackOverflowException(); 

si potrebbe fare questo durante il test o fare fault-iniezione.

+1

Ottimo, supponendo che si stia utilizzando .NET =) –

1

Se si sta parlando di C++ con una libreria standard ragionevole, ho un'immagine che questo dovrebbe funzionare:

while (true) { 
    alloca(1024 * 1024); // arbitrary - 1M per iteration. 
} 

Dettagli sulla alloca.

+0

È un'eccezione di stackoverflow o di memoria insufficiente? – Juliet

+2

@juliet: la funzione alloca() alloca lo spazio nel frame dello stack del chiamante. – pierrotlefou

+2

Questo non dovrebbe generare un'eccezione se alloca() è implementato correttamente. La chiamata alloca() dovrebbe restituire NULL se non c'è abbastanza spazio nello stack piuttosto che generare un'eccezione. Quello che dovrebbe accadere è che dopo aver esaurito lo spazio di stack, il tuo codice sarà bloccato in un ciclo infinito di chiamate alloca() restituendo valori NULL. – Adisak

2

Risposta breve: se si dispone di un oggetto che richiama un oggetto interno, si aumenta la traccia di stack di 1. Quindi, se ci sono 1000 di oggetti annidati l'uno dentro l'altro, ognuno chiama il suo oggetto interno, alla fine si otterrà uno stack overflow.

Ecco una dimostrazione di come generare numeri primi utilizzando iteratori nidificate:

using System; 
using System.Collections.Generic; 
using System.Text; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Program p = new Program(); 

      IEnumerator<int> primes = p.AllPrimes().GetEnumerator(); 
      int numberOfPrimes = 1000; 
      for (int i = 0; i <= numberOfPrimes; i++) 
      { 
       primes.MoveNext(); 
       if (i % 1000 == 0) 
       { 
        Console.WriteLine(primes.Current); 
       } 
      } 
      Console.ReadKey(true); 
     } 

     IEnumerable<int> FilterDivisors(IEnumerator<int> seq, int num) 
     { 
      while (true) 
      { 
       int current = seq.Current; 
       if (current % num != 0) 
       { 
        yield return current; 
       } 
       seq.MoveNext(); 
      } 
     } 

     IEnumerable<int> AllIntegers() 
     { 
      int i = 2; 
      while (true) 
      { 
       yield return i++; 
      } 
     } 

     IEnumerable<int> AllPrimes() 
     { 
      IEnumerator<int> nums = AllIntegers().GetEnumerator(); 
      while (true) 
      { 
       nums.MoveNext(); 
       int prime = nums.Current; 
       yield return prime; 

       // nested iterator makes a big boom  
       nums = FilterDivisors(nums, prime).GetEnumerator(); 
      } 
     } 
    } 
} 

Non c'è la ricorsione, ma il programma lancerà un'eccezione di overflow dello stack dopo circa 150.000 numeri primi.

+0

ncie code, mi ricorda Evolution of Haskell programmer :) (tonnellata di codice contro oneliner - programmazione di un fattoriale) –

7

Quanto segue si applica a Windows, ma la maggior parte dei sistemi operativi lo implementa in modo simile.

La risposta breve è: se si tocca l'ultima pagina di guardia, verrà lanciata.

Un'eccezione di tipo EXCEPTION_STACK_OVERFLOW (C00000FD) viene sollevata quando l'applicazione tocca la pagina inferiore della pila, contrassegnata da un flag di protezione PAGE_GUARD e non c'è spazio per far crescere lo stack (eseguire il commit di un'altra pagina), vedere How to trap stack overflow in a Visual C++ application.
Il caso tipico in cui ciò accade è quando la pila è cresciuta come risultato di molti fotogrammi funzione nello stack (ad esempio fuori ricorsione di controllo), come risultato di un numero inferiore di fotogrammi ma di dimensioni di fotogrammi molto grandi (funzioni con molto grandi oggetto ambito locale) o allocando esplicitamente dallo stack con _alloca.
Un altro modo per causare l'eccezione è semplicemente toccare intenzionalmente la pagina di guardia, ad es. dereferendo un puntatore che punta in quella pagina. Questo può accadere a causa di un bug di inizializzazione variabile.

Gli overflow dello stack possono verificarsi su percorsi di esecuzione validi se l'input causa un livello di nidificazione molto elevato.Per esempio vedi Stack overflow occurs when you run a query that contains a large number of arguments inside an IN or a NOT IN clause in SQL Server.

-1

Il modo più semplice per fare uno StackOverflowException è la seguente:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      SomeClass instance = new SomeClass(); 
      string name = instance.Name; 
     } 
    } 

    public class SomeClass 
    { 
     public string Name 
     { 
      get 
      { 
       return Name; 
      } 
     } 
    } 
} 
+1

In realtà questo è il 2o modo più semplice dopo aver lanciato l'eccezione :) –

+3

La domanda esclude specificamente la ricorsione. – meriton

+0

Hai ragione, mio ​​errore. –

0
int main() 
{ 
    //something on the stack 
    int foo = 0; 
    for (
    //pointer to an address on the stack 
    int* p = &foo; 
    //forever 
    ; 
    //ever lower on the stack (assuming that the stack grows downwards) 
    --p) 
    { 
    //write to the stack 
    *p = 42; 
    } 
}