5

I'd like to be able to predict the number of recursive calls that fit on the stack before a StackOverflow exception happens. For this, I'd need to find out the 'footprint' of a given method call on the stack.

Is there a way to do this programmatically? I looked into System.Diagnostics.StackFrame and System.Diagnostics.StackTrace but couldn't find anything relevant.

Empirically, using this simple example, I found the footprint to be quite different for:

  • 32 bit vs 64 bit: ~22k vs ~8k frames (does different pointer size account for the ~3x increase?)
  • debug vs release: ~22k vs ~64k frames (Debug builds add all sorts of special-pattern bounds-checking padding + debugging instrumentation)
  • Non-optimized vs optimized:
    • ~22k vs ~51k in Debug (expected - less debug info)
    • ~64k vs ~51k in Release (that's strange! maybe some memoization techniques are employed?)
  • Debugger attached vs not attached: it's amazing what a difference this makes in the jitted code!
    • 85k vs 258k - Release, Optimizations ON
    • 14k vs 64k - Debug, Optimizations OFF

Most likely different versions of .NET also yield different results.

To sum it all up:

Seeing that the stack frame size varies so wildly with these parameters, is there a programmatic way to figure out the stack frame size for a given method at runtime?

How about 'offline' (manually)? Maybe at least for the straight-up, Release, non-optimized build?

Community
  • 1
  • 1
Cristian Diaconescu
  • 34,633
  • 32
  • 143
  • 233
  • Why not just refactor the given method into a non-recursive implementation so you don't need to worry about blowing out the stack? – Servy Nov 27 '13 at 15:39
  • I would say size of local variables, including return value and return address. Of course class references count only as the pointer (32 or 64 bits). If your call is in the middle of an expression, also add space for the temporal variable being used. This would be a maximum, the compiler might optimize it (for instance reusing a memory location of a variable that is no longer used). – SJuan76 Nov 27 '13 at 15:41
  • 1
    @Servy it's a theoretical question, not a real problem burning to be solved :) I always learn something new when poking around under the hood - like I did just now with the data I got from my little experiment. – Cristian Diaconescu Nov 27 '13 at 15:45
  • 1
    Easy to make the call, it is O(log(n)). Since allowing a recursive algorithm with higher complexity is *always* a mistake and is guaranteed to bomb your program sooner or later. – Hans Passant Nov 27 '13 at 16:40
  • 2
    @HansPassant [Citation needed]? This sounds like a good rule of the thumb, but what's backing it up? Based on your history of answers, I'm *pretty sure* there's a basis behind that statement. – Cristian Diaconescu Nov 28 '13 at 10:22

0 Answers0