Hello, I have been looking for some game developments on Nim and I found the following: https://github.com/mrsekut/nim_platform_game
A platforms game made in Nim.
Well, the problem with this is that if I compile with arc or orc my RAM memory gets filled slowly but steady. If I use the default GC or I don't use GC at all, memory is handled properly, well, I mean, it doesn't keep taking more memory.
When I say that my RAM gets filled up, I'm talking about the "Mem" field on top of htop.
I would like to know why this happens.
On void linux I had to install SDL2-devel, SDL2_image-devel and SDL2_ttf-devel and sdl2 from nimble. I'm not sure if it is needed anything else.
To compile the program I had to use the nim binary directly instead of nimble, as it throws and error. And I also had problems compiling the code, I guess because of version compatibility issues, I made a patch to solve the problem, although I don't know if what I did was the best approach (I just replaced "time" with "game.player.time")
Patch: https://envs.sh/j2.patch
What Nim version are you on? For me on devel (355985ac89dd13d5b317744b30842155d9321565) there are no leaks with ARC/ORC with that game. Also, you don't need that patch, you can just change a single line 236 so that it becomes
template time: untyped = game.player.time
I think I found out the issue:
template rendertextCached(game: Game, text: string, x, y: cint, color: Color) =
block:
var tc {.global.} = newTextCache()
game.renderText(text, x, y, color, tc)
{.global.} doesn't really play well with ARC/ORC, see https://github.com/nim-lang/Nim/issues/15005 which I suspect is the root cause of this leak as well.
type
TextCache = ref object
var cnt = 0
proc newTc(): TextCache =
inc cnt
result = TextCache()
proc use(tc: TextCache) = discard
template renderTextCached(text: string) =
block:
var tc {.global.} = newTc()
use(tc)
proc main =
for x in 0..5:
renderTextCached("hi")
main()
echo cnt
Outputs 1 with refc, 6 with ARC/ORC - each time a new variable is created.
not use the global pragma
You may not be able to avoid it. It is the "static" from C variables, we need it when variables in procs should remember its state between proc calls.
yes i wonder how {.global.} can be replaced when used for a static var (its main use, i guess). I have read the github discussion and even if i don't understand everything, the issue seems serious.
But if i understand well, the solution would be to use « global top level variables », that is indeed « global variable » definition. But the main advantage of {.global.} (i don't like this name which does not reflect the main purpose) is to be used as static variable.
I'm looking forward for a workaround, but honestly i see nothing excepts «real» global variables (iiiirk) or the need to add another parameter when calling function, with all the micro-management that implies.
Personally I would avoid {.global.} and "static" in C too, just like I would avoid global variables. Why not create a state object for all your state and pass it around?
I know it's a bit more painful but it avoids a lot of problems and makes your code far better organised.
There's a workaround to make global with ARC work more-or-less like it does with refc:
proc test2 =
var greeting {.global.}: string
# from system
once:
greeting = "hi"
greeting &= "hi"
echo greeting
test2() # hihi
test2() # hihihi
test2() # hihihihi
test1 only works with refc correctly, test2 works with both refc/ARC