0

I have a c# application which I used to run on a XP machine. I switched recently to a Windows 7.0 machine.

I have the following error message when being in debugger: "System.StackOverflowException". Still have the XP machine, don't have the problem with this one.

It's overflowing in the middle of a recursive algorithm. Anyone familiar with this problem? Is that the OS which has to do with this or is that the machine itself?

Many thanks for your help,

Michael

Michael
  • 111
  • 1
  • 2
  • 4
  • 9
    Can you post some code? It might help to see what it is. – NominSim Jul 17 '12 at 15:44
  • 2
    Can you provide us with the hardware specifications? RAM is the most important – Alvin Wong Jul 17 '12 at 15:49
  • 2
    @AlvinWong I don't believe this is a hardware problem. Running out of stack space means that the process used the 1 MB allocated for the stack of the thread in question. – Brian Rasmussen Jul 17 '12 at 16:10
  • @Brian Rasmussen - you're absolutely correct. It is *not* a h/w issue :) – paulsm4 Jul 17 '12 at 16:12
  • Well, it could be; check my answer. Win7 has more RAM-resident stuff, and also allocates RAM differently meaning that a thread might not be getting the full 1MB for its stack. – KeithS Jul 18 '12 at 15:16

3 Answers3

1

It would be helpful to know just how deep the recursion goes in XP before reaching the base case, and where it errors in Win7.

Theoretically, a Windows 7 process should have more available stack space than a WinXP process; at the very least, they should be the same. However, there are other factors at play here. Check out this blog post: http://blogs.technet.com/b/markrussinovich/archive/2009/07/08/3261309.aspx

In short, the limiting factor is usually "resident available memory"; this is physical RAM (not page file space) that is available for data that must be kept there and can't be swapped to the page file. A lot of things must be kept "resident" on the average computer and cannot be swapped out to the page file; most important is that anything that must be run in "kernel mode" (requiring direct access to the core system) must be kept in RAM to avoid page faults, even when there are no active threads for that process at the time.

Windows 7 has more of these "kernel-mode" processes. For instance, Windows Aero (which wasn't part of WinXP) uses your graphics card to accelerate rendering of the desktop, and so it must run in kernel mode. The Windows 7 kernel itself is larger, because it includes additional security and additional built-in hardware support. Windows 7 also has additional background processes etc that run in kernel mode that weren't in WinXP.

So, all other things being equal (including RAM), a Windows 7 machine will actually have less resident memory available to commit to your recursive algorithm, meaning that the algorithm will not be able to recurse deeply enough to reach the base case before a call triggers a StackOverflowException due to Windows not having enough resident memory to meet the "commit" required for the new call.

In addition, Windows 7 arranges things in memory differently. Older Windows versions (XP and older) reserved a memory space for each new process in roughly sequential fashion; the N+1th process (or thread) is given a memory address one block after the last one reserved for the Nth process/thread. Beginning with Windows Vista, memory was allocated in a more "random" fashion; Windows will choose a location in memory that may or may not be adjacent to any other reserved block (it's only guaranteed not to be a part of any other reserved block). This is a security feature designed to confuse malware and prevent it from successfully snooping around in other processes' memory. However, the less space-efficient allocation scheme means that the OS will more quickly run out of 1MB blocks of contiguous RAM to allocate to each new thread. At that point, it begins allocating the gaps. So, depending on your Windows 7 machine's specific memory usage footprint, the thread for your recursive function may request the usual 1MB of stack space, and be given a pointer by the OS which actually only has 128K of contiguous space. Your program won't be able to tell the difference, until it can't actually commit all the space it thought it had reserved. This can produce Heisenbugs where it'll work one time but fail the next because of non-deterministic differences in the exact memory space Windows reserves for the thread each time.

The answer to all of this is "more RAM". The amount needed by the core kernel-mode processes is relatively static, so every GB of additional RAM you can add is a GB that is available solely for user program processes and threads.

KeithS
  • 70,210
  • 21
  • 112
  • 164
0

How recursive is recursive?

Anything deeper than about ten or so could be risky.

If you're exhausting the stack and you're sure it's not a bug, you could manage your own stack...

For instance:

void Process(SomeType foo)
{
    DoWork(foo); //work on foo
    foreach(var child in foo.Children)
    {
        Process(child);
    }
}

could become

void Process(SomeType foo)
{
    Stack<SomeType> bar=new Stack<SomeType>();
    bar.Push(foo);
    while(bar.Any())
    {
        var item=bar.Pop();
        DoWork(item);//work on item
        foreach(var child in item.Children)
        {
            bar.Push(child);
        }
    }
}

thus eliminating any CLR call-stack problems.

Of course, this won't fix an unbounded recursion.

Community
  • 1
  • 1
spender
  • 117,338
  • 33
  • 229
  • 351
0

I don't believe this has anything to do with the physical RAM on your PC. I suspect the reason you didn't happen to see it on XP is simply that Windows 7 probably has a (slightly?) different version of .Net.

Clearly, you need to somehow limit the depth of your recursion (or substitute a non-recursive loop).

But you can potentially configure your .Net stack(s). Please look at these links:

Community
  • 1
  • 1
paulsm4
  • 114,292
  • 17
  • 138
  • 190