In the deferred reference counter which is the default GC, the following code execution is very slow.
This is probably because that always scan zct when memory is allocated, by the number of objects retain to the variable always exceeds the threshold ( = ZctThreshold = 500).
Is this behavior expected? change threshold dynamically is not good?
1. Deep recursive procedure
proc recursive(pos:int):int =
if pos == 100_000: return 0
if pos mod 100 == 0: echo GC_getStatistics(),pos
var a = newSeq[int](1) # slow here
return recursive(pos+1) + a[0]
echo recursive(0)
2. Get array of many object
import sequtils
type Obj = ref object
proc many():int =
# get many object
var mat:array[10_000, Obj]
for s in mat.mitems:
s = new(Obj)
# loop
var sum = 0
for i in 0..<100_000:
if i mod 100 == 0: echo GC_getStatistics(),i
var a = newSeq[int](1) # slow here
sum += a[0]
return sum
echo many()
https://github.com/nim-lang/Nim/blob/devel/lib/system/gc.nim
The problem is not the GC, it's that you are allocating heap memory in a tight loop. Refcounting is deferred, if an object is created and destroyed within the same procedure scope there is no counter overhead.
If you malloc in a for(int i = 0; i < 100_000; i++) loop in C it will be just as slow.
The way around that is to not heap allocate in a tight loop. You can reallocate the array before the loop and reuse as a buffer/scratch space inside for example.
What about our awesome soft real-time GC?!
It makes Nim more useful for hard real-time. I don't think it's a bad trade-off.