Hi forum,
Recently I’m doing some experiments on manual memory management using Crystal, first I was trying to check how to fit a Rust-like ownership model into the language, then I realize that there’s a faster way to accomplish this without even touch the compiler, i.e. by using a C++ like memory management model (most people stop reading here). Let’s ignore the problems caused by manual memory management and focus on the problem:
How to have a deterministic memory usage on programs written in Crystal that need this for whatever reason?
I found a simple and stupid way to accomplish this with this snippet of code:
{% unless flag?(:gc_none) %}
{% raise "You want to leak memory or not!? so use -Dgc_none" %}
{% end %}
@[AlwaysInline]
def free(ptr : Pointer) : Nil
GC.free(ptr.as(Pointer(Void)))
end
@[AlwaysInline]
def free(obj : Reference) : Nil
obj.finalize
# pointerof(obj) is a pointer to the local variable obj, but we need the pointer to what it points to.
free pointerof(obj).as(Pointer(Void*)).value
end
class Array(T)
def finalize
free @buffer
end
end
class String
def finalize
end
end
# Now using it:
a = [1, 2] of Int32
free a
a = 42
str = "hey #{a}"
free str
After few small tests with Array and non-literal strings it worked… despite of always leak 8K according with valgrind.
Good things about this approach:
- Not a different language, everything still Crystal, just more dangerous and probably leaking some memory
- Can be done in a shard.
Bad things about this approach:
- Need to monkey patch a lot of classes in stdlib.
- Temporary objects will leak, e.g.
"hey" + "ho" +"leak" + "baby"
. - Trying to do
free "string literal"
will crash, since the memory is probably in a readonly memory page, causing free call to fail withfree(): invalid pointer
So finally the question: Is there a way to know if a string comes from a string literal or if it was built at runtime?
I’m doing all this for fun, so answers like: Use language X, Why you don’t like a GC, etc are useless.
Thanks.