I'm trying to understand how the garbage collector works so that I can properly implement GC support for Nintendo Switch. I have a basic implementation, but DeAlloc-ing never seems to happen, even when the program exits (which is a problem because all allocated memory has to be cleaned up, it seems). So, to try to understand when deallocs happen, I put some print statements in the Unix side of osalloc.nim:
proc osAllocPages(size: int): pointer {.inline.} =
c_fprintf(stdout, "[Alloc] size %d\n", size) # my print statement
result = mmap(nil, size, PROT_READ or PROT_WRITE,
MAP_PRIVATE or MAP_ANONYMOUS, -1, 0)
if result == nil or result == cast[pointer](-1):
raiseOutOfMem()
proc osTryAllocPages(size: int): pointer {.inline.} =
result = mmap(nil, size, PROT_READ or PROT_WRITE,
MAP_PRIVATE or MAP_ANONYMOUS, -1, 0)
if result == cast[pointer](-1): result = nil
proc osDeallocPages(p: pointer, size: int) {.inline.} =
c_fprintf(stdout, "[DeAlloc] size %d\n", size) # my print statement
when reallyOsDealloc: discard munmap(p, size)
I then made a simple program that loads some memory with a GC'd object to see what happens.
# test.nim
type
Obj = ref object
foo: int
proc testing(): Obj =
Obj(foo: 300)
var obj = testing()
echo obj.foo
When I run the program with nim c -r test.nim, I get:
[Alloc] size 524288
[Alloc] size 4096
Hint: used config file '/home/joey/Nim/config/nim.cfg' [Conf]
Hint: system [Processing]
[Alloc] size 524288
[Alloc] size 524288
[Alloc] size 524288
[Alloc] size 524288
Hint: test [Processing]
CC: test
Hint: [Link]
Hint: operation successful (12033 lines compiled; 0.194 sec total; 16.324MiB peakmem; Debug Build) [SuccessX]
Hint: /home/joey/Downloads/scratch/test [Exec]
[Alloc] size 524288
[Alloc] size 4096
300
So I get the allocs, but the deallocs never seem to happen. I thought maybe the GC just didn't collect my object or didn't have a chance to run. So I put a call to GC_fullCollect() at the bottom of the file. Still the same output!
So, am I misunderstanding how the GC works? Does it do a full deallocation on program exit that exists somewhere else?
proc deallocOnQuit() {.noconv.} =
deallocHeap(runFinalizers = true, allowGcAfterwards = false)
addQuitProc deallocOnQuit