I’m really curious why it would crash there, when displaying the solution, because basically no dynamic memory allocation happens at that point. Here’s the relevant code:
(get input $)
Knaves:
(exhaust) {
*($Knave is one of $KnaveList)
(name for index $Knave)
}
So it just iterates over the list and prints the name of each one. Purely iterative code.
Hmm…I wonder if the main heap is used for things like lists, and the auxiliary heap is used for choice points?
This is a quote from Stackoverflow on the NET heaps:
There are 3 heaps + the large object heap. All objects are allocated in heap 0. If they survive one garbage collection they’re promoted to heap 1, then to heap 2, and then stays there until collected. The large object heap (LOH) is for objects which are 85000 bytes or more in size (not in total, continous, like arrays). Where you got the fifth heap from I don’t know.
I suspect the different heaps in dg are used in some smiliar manner (gen0–>gen1–>gen2, or maybe gen0–>gen1 + a LOH).
Unfortunately the source of dg is extremely sparsely commented so it’s hard to know. I can’t find something that looks like a GC, but guess it must be there somewhere. Commenting up the code could be a separate project on its own.
Yeah, there’s very little commenting and no repository with commit comments or history, which makes modifying anything a fraught prospect. Sadly. The auxiliary heap is allowed to be a lot bigger than the main heap, and the long-term heap seems to contain the initial values of variables (if they point into dynamic memory), but beyond that…
I ran some test with different values for the heap sizes (z5 and run on Window Frotz).
dialogc -v -t z5 -H 1000 -A 500 -L 100 knaves2.dg
6 6 12 Peak dynamic memory usage: 1000 heap words, 327 aux words, and 0 long-term words.
dialogc -v -t z5 -H 2000 -A 500 -L 100 knaves2.dg
8 8 16 Peak dynamic memory usage: 2000 heap words, 358 aux words, and 0 long-term words.
dialogc -v -t z5 -H 4000 -A 500 -L 100 knaves2.dg
13 13 26 Peak dynamic memory usage: 4000 heap words, 413 aux words, and 0 long-term words.
dialogc -v -t z5 -H 6000 -A 500 -L 100 knaves2.dg
15 15 30 Peak dynamic memory usage: 5841 heap words, 500 aux words, and 0 long-term words.
dialogc -v -t z5 -H 8192 -A 600 -L 100 knaves2.dg
19 19 38 Peak dynamic memory usage: 8192 heap words, 516 aux words, and 0 long-term words.
The heap is the one that grows fastest with the array size and the crash when this heap gets exhausted always occurs when building the array and listing the different persons statements.
The auxheap doesn’t grows as fast but when it gets exhausted it’s always when presenting the result.
The long-term heap isn’t used at all in Knaves.
Finding some ideal values for Knaves would maybe max for the heap (-H 8192), make the auxheap a bit bigger than the default (-A 1000) and minimize the long-term (-L 100).
(Is there any way to see the heap values without finding the edge case and crashing the game? I can’t find anything in dgdebug.)
(display memory statistics) is what’s printing those values right before the crash, so you can call that at any point instead of only in the (error $ entry point) to see how much has been used. Note that it only displays the peak usage during the game, not the current usage.
Oh, also note that dgdebug specifically doesn’t do tail call optimization; it just dynamically allocates more memory for the call stack if necessary. So it shouldn’t crash due to that, but it could throw the memory usage analysis off.