[Haskell-cafe] Haskell maximum stack depth
ahey at iee.org
Mon Feb 4 17:13:12 EST 2008
Neil Mitchell wrote:
>> First bad thing:
>> Stack size (memory consumed) doubles each time it overflows.
> Bad thing? Assume that allocating memory takes some constant amount of
> time, such as invoking overflow behaviour etc. To get the size of the
> stack to n bytes with doubling takes O(log n), to get it there with a
> constant increase takes O(n).
But whatever the program did to get given stack size must have
been at least O(n) anyway, so overall it's still going to be O(n)
even if the stack allocation part is O(log n). We're just talking
about a very tiny increase in constant factors, at least if Stefan
O'Rears hypothesis is correct :-). I'm inclined to agree with him.
> If you store the stack in a linear
> block, then allocation costs O(n) and you can even risk O(n^2)
> behaviour unless you double each time. I think its fairly well
> understood that things like hash tables should double in size when
> they overflow, rather than increasing by some small increment.
It is? Well obviously if the entire thing is copied each time this
will be bad, but that's not what we're talking about. See Stefans
> remember that this behaviour never wastes more than 50% of the stack,
> which is a relatively small amount.
Only if the stack is relatively small. Would you say the same about
heap, or about a stack that only needed 50% of heap space but ended
up using all of it? Or money? Using twice as much as you need of
anything is bad IMO.
>> Third bad thing (the really bad thing):
>> If a stack has temporarily grown (to 64M say), it will never shrink
>> back down again to something more typical (< 4K say). If I understand
>> correctly, it will continue to take 64M from the heap regardless.
> That would be nice. But its only beneficial if there are programs
> which takes large amounts of stack at some point, but then shrink down
> to very little stack and continue for a reasonable amount of time.
> Console programs probably don't fit this pattern (since they tend to
> be batch style and exit quickly). GUI programs probably do, so perhaps
> stack reduction will be more important as the GUI toolkits mature and
> Haskell starts getting used for UI type things.
The nature of the app has nothing to do with it AFAICS, this problem
can affect any program that evaluates expressions.
> That said, unless
> there is a real user with a real problem (rather than a theoretical
> concern), priority may go to other bugs.
The point is that writing a stack greedy function definition (rather
than a heap greedy alternative) is almost always the simpler option,
and would probably be more efficent too. It would also be perfectly
OK in *most* situations.
But being OK in most situations isn't good enough. You also (as far
as is possible given finite amount of total memory) want it to be
OK in "pathological" situations, or at least no worse than the heap
greedy version. Why should the decision to use a stack greedy definition
cause a crash at 8M whereas a heap greedy definition can happily use
much more without crashing?
I (like everyone else) tend to avoid knowingly writing stack greedy
definitions because of this. But I do this as a workaround for ghc's
currently (IMO) poor stack management, not because I consider code
that uses the stack to be inherently buggy.
Furthermore as I said earlier, "using a lot of stack" is purely a
ghc rts implementation detail. Other possible Haskell implementations
may not use a lot of stack for the same function (may not use a stack
at all). So you can't say a program has bugs just because it happens
to cause a "stack overflow" with ghc. You might reasonably argue that
it has a bug if it uses a lot of memory with any plausible Haskell
implementation (one way or another) *and* you can show that there is
an alternative implementation which uses asymptotically less memory.
More information about the Haskell-Cafe