1

What does stack overflow actually mean in a .Net garbage collected world?

Karel
  • 2,112
  • 1
  • 15
  • 25

7 Answers7

11

Exactly the same thing as it does everywhere else - you've blown the stack, usually because you've recursed badly. For example:

public int Foo(int x)
{
    return Foo(x + 1);
}

Now this example may get optimized with tail-recursion, in which case it will just run forever - but otherwise (and in a more general case where tail-recursion isn't feasible), this will push a new stack frame for each recursive call to Foo... and those stack frames will never be popped, as the calls will never actually return.

This has nothing to do with garbage collection.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Should make this `return 1 + Foo(x +1)` to avoid a potential tail recursion optimization – JaredPar Apr 01 '11 at 16:41
  • @JaredPar: I was just editing to mention that. I think it's better to just mention that it can happen than try to work around it in this case... who knows how smart the CLR could get? :) – Jon Skeet Apr 01 '11 at 16:42
  • very true on CLR smarts. The F# team in particular would love to see it get smarter here. – JaredPar Apr 01 '11 at 16:43
  • See also [here](http://stackoverflow.com/questions/194484/whats-the-strangest-corner-case-youve-seen-in-c-or-net/195824#195824) . Apparently tail-call optimizations depend on whether running 64bit or 32bit. – Brian Apr 01 '11 at 16:52
3

A stack overflow and garbage collection are essentially orthogonal concepts: stack vs. heap. The purpose of the garbage collector is to reclaim unreachable objects which live in the heap. A stack overflow occurs when the execution stack exceeds the limit allowed by the current thread. All items on the stack are by definition reachable hence the garbage collector can do nothing to "clean up" the stack

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • It felt wrong for my answer to get an up-vote in-lieu of yours. – ChaosPandion Apr 01 '11 at 16:43
  • @ChaosPandion thanks! How and why people up vote is still a mystery to me. Just last night someone took the time to comment about how much they liked my answer but didn't bother to up vote it??? – JaredPar Apr 01 '11 at 16:45
2

StackOverflowException! The exception that is thrown when the execution stack overflows because it contains too many nested method calls.

Basically starting with the .NET Framework 2.0, a StackOverflowException object cannot be caught by a try-catch block and the corresponding process is terminated by default. Consequently, users are advised to write their code to detect and prevent a stack overflow. For example, if your application depends on recursion, use a counter or a state condition to terminate the recursive loop.

Mr. Young
  • 2,364
  • 3
  • 25
  • 41
2

In software, a stack overflow occurs when all the memory is used on the call stack, and thus no more methods can be called.

Richard
  • 106,783
  • 21
  • 203
  • 265
ChaosPandion
  • 77,506
  • 18
  • 119
  • 157
1

.NET still uses the stack to allocate local variables (and the rest of the stack frame), so it means pretty much the same thing it always has. The only difference is that it throws an exception, which can be caught in .NET versions below 2.0. However, it is challenging to write code that correctly recovers from this condition. Thus, current versions no longer allow you to catch it. However, stack overflows don't cause undefined behavior in any version of .NET.

Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
1

It has little to do with .NET, the stack is an implementation detail of the processor. Just about any programming language needs to deal with it in order to get acceptable performance, it often affects the design of the language a great deal.

The very first thing the processor stack supports is calling subroutines. The CALL instruction pushes the value of the instruction pointer on the stack and jumps to a chunk of code. Which completes with the RET instruction, it pops the instruction pointer value back off the stack and execution continues where it left off, at the instruction after the CALL instruction. You'll recognize this as a method in .NET languages.

A subroutine often needs to work with variables passed from the calling code. At the processor level this works by pushing their value on the stack with the PUSH instruction. The called subroutine then reads their value by indexing the stack at a well-known location. You'll recognize this as a method parameter in .NET languages.

A subroutine often needs some memory to store intermediary values. A cheap way to get some is to adjust the stack to create some space on it. You'll recognize this as a method's local variables.

As you can see, any method call in .NET consumes some space from the stack. To store the return address, method arguments and local variables. It is a limited resource however, the processor stack can grow up to one megabytes on a 32-bit operating system. The default value, it is technically possible to ask for more space.

Trouble arises when a method calls another method which calls another method, etcetera. Each method occupies space. This cannot go on for ever, eventually the processor runs out of stack space. That's the Big Kaboom, StackOverflowException in .NET. At its core it is a low-level operating system fault. Recovering from an SOE is impossible, the primary mechanism by which code runs on a processor is faulty. You cannot catch the exception, your program dies an instant death.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
0

Quite a common mistake in .NET is something like:

private int someProperty;
public int SomeProperty
{
    get { return SomeProperty; }
    set { SomeProperty = value; }
}

Which will give you a StackOverflowException. The only clue is a warning that someProperty is never used.

Chris Ballard
  • 3,771
  • 4
  • 28
  • 40