Community
SCI Programming => SCI Community How To's & Tutorials => Topic started by: troflip on November 10, 2015, 02:04:23 PM
-
I haven't yet encountered any "out of heap space" errors in SCI1.1, but I'm sure it could happen. And unlike SCI0, there is no built in debugger to show you object addresses.
It would be cool if someone could have an in-game "bar graph" that shows where heap is being used. Then you could mouse over it and it would tell you which object is at a particular location.
As a start, you could identify all the objects in memory. Here's some code to do that:
(define UNLISTED_VAR_COUNT 4)
(define VAR_OFFSET 8)
(define NAME_OFFSET_OFFSET 16)
(procedure (FindNextObject start)
(var i, value)
(= i start)
(while (<u i $fffe)
(= value Memory(memPEEK i))
(if (== value $1234)
// Found an object
break
)
(+= i 2)
)
return (i)
)
(procedure (PrintObjectName location)
(var listVarCount, endExclusive)
(= listVarCount Memory(memPEEK (+ location 2)))
(-= listVarCount UNLISTED_VAR_COUNT) // First 4 vars aren't listed
(= endExclusive (+ (+ location VAR_OFFSET) (* listVarCount 2)))
DebugPrint("%x - %x: %s" location endExclusive Memory(memPEEK (+ location NAME_OFFSET_OFFSET)))
)
And then somewhere:
// Look for objects
(= i 0)
(while (<u i $fffe)
(= i PrintNextObject(i))
PrintObjectName(i)
(+= i 2)
)
That will print out (in the debug console) all the objects and the range of heap space they take up.
That would probably be sufficient to diagnose any "out of heap" errors. Of course, there are still other things in the heap. The rest of the heap script data, like global variables and strings. And explicit memory allocations (i.e. Memory(memALLOC...)) It doesn't look like the hep resources are copied wholesale into the heap. They are at least re-arranged a bit, because classes seem to come before instances, despite how they are laid out in the hep resource.
It might be possible to work at this from a lower level too... to track actual memory blocks being allocated. If you allocate something with Memory(memALLOC ...), you'll see that just before the memory block is a 16-bit integer that indicates its size. There must be a pointer to this heap allocation somewhere too, but I haven't found it. I'm not sure if the hep resources that are loaded would follow the same pattern though (i.e. being preceded by "size" marker).
-
Thanks for this sample code Troflip. I didn't go as far as you suggested, but I did wire it into where the debugging usually goes within Main.sc
(define UNLISTED_VAR_COUNT 4)
(define VAR_OFFSET 8)
(define NAME_OFFSET_OFFSET 16)
(procedure (FindNextObject start &tmp i value)
(= i start)
(while (u< i $fffe)
(= value (Memory memPEEK i))
(if (== value $1234)
; Found an object
(break)
)
(+= i 2)
)
(return i)
)
(procedure (PrintObjectName location &tmp listVarCount endExclusive)
(= listVarCount (Memory memPEEK (+ location 2)))
(-= listVarCount UNLISTED_VAR_COUNT) ;First 4 vars aren't listed
(= endExclusive (+ (+ location VAR_OFFSET) (* listVarCount 2)))
(if (u> location endExclusive)
(return FALSE)
)
(DebugPrint "%x - %x: %s" location endExclusive (Memory memPEEK (+ location NAME_OFFSET_OFFSET)))
)
At first, I was getting an infinite loop when I ran the code until I added a check to make sure that the start address had to be before the end address - not sure it was the right solution or not, but it seemed to work.
Then I just added this case in the handleEvent
(KEY_ALT_o ; show all objects in memory
(= i 0)
(while (u< i $fffe)
(= i (FindNextObject i))
(if (not (PrintObjectName i))
(break)
)
(+= i 2)
)
)
With this, I was able to determine that dynamic scripts that were being loaded by my game were never being unloaded. From there I was able to mitigate the issue.