I was tracking down a memory issue when I encountered an unexpected the behavior of ORC/ARC when using custom finalizers.
I'm using new function to assign a finalizer to a type. https://nim-lang.org/docs/system.html#new%2Cref.T%2Cproc%28ref.T%29
Not sure if this is worth a github issue, please let me know. Here a small test to expose the problem.
Compile with --gc:arc
const n = 0
when n == 0: # RootObj + forward declaration
# Custom finalizer not called
type Foo = ref object of RootObj
proc delete(self: Foo)
proc newFoo: Foo = new(result, delete)
proc delete(self: Foo) = echo("delete Foo")
when n == 1: # RootObj + no forward declaration
# Working correctly
type Foo = ref object of RootObj
proc delete(self: Foo) = echo("delete Foo")
proc newFoo: Foo = new(result, delete)
when n == 2: # no RootObj + forward declaration
# Error: internal error: expr: proc not init delete
type Foo = ref object
proc delete(self: Foo)
proc newFoo: Foo = new(result, delete)
proc delete(self: Foo) = echo("delete Foo")
when n == 3: # no RootObj + no forward declaration
# Working correctly
type Foo = ref object
proc delete(self: Foo) = echo("delete Foo")
proc newFoo: Foo = new(result, delete)
if isMainModule:
discard newFoo()
I've extended the experiment to --gc:refc, this also is giving me some unexpected results: finalizers seems never called even after GC_fullCollect()
Compile with --gc:refc
const n = 0
when n == 0: # RootObj + forward declaration
# Custom finalizer not called
type Foo = ref object of RootObj
proc delete(self: Foo)
proc newFoo: Foo = new(result, delete)
proc delete(self: Foo) = echo("delete Foo")
when n == 1: # RootObj + no forward declaration
# Custom finalizer not called
type Foo = ref object of RootObj
proc delete(self: Foo) = echo("delete Foo")
proc newFoo: Foo = new(result, delete)
when n == 2: # no RootObj + forward declaration
# Custom finalizer not called
type Foo = ref object
proc delete(self: Foo)
proc newFoo: Foo = new(result, delete)
proc delete(self: Foo) = echo("delete Foo")
when n == 3: # no RootObj + no forward declaration
# Custom finalizer not called
type Foo = ref object
proc delete(self: Foo) = echo("delete Foo")
proc newFoo: Foo = new(result, delete)
if isMainModule:
discard newFoo()
GC_fullCollect()
@giaco:
What you are missing is that things that are allocated globally aren't collected; you need to allocate locally inside a function/proc in order to qualify for collection:
You need to declare your test code as follows:
if isMainModule:
let mem0 = getOccupiedMem()
proc test() = discard newFoo()
test()
GC_fullCollect()
echo (getOccupiedMem() - mem0)
The above completely works for normal GC, and with Arc/Orc works for case 1 and 3, doesn't call the destructor for case 0, and generates a compiler error for case 2 for both Arc and Orc, this with Nim version 1.4.8 up to devel latest.