Proper way for Allocation/Deallocation of objects

Hello :slight_smile:

I would love to understand the allocation/deallocation of long-life-objects in Oxygene better and for that i need to know, how actually is the best way to do this:

Is it not to care about the memory_management

(or) to care with the “gc.h” headerfile functions, mostly: GC_malloc, GC_malloc_atomic, GC_free and so on…

Which way you would prefer for a clean and at the same time, fast code :slight_smile:

Yours,
Shpend

hi, I take it from the “gc.h” reference you’re using island? gc.h is an internal detail really, the RTL uses it to allocate (it’s a gc so it will clean up as soon as you clear all references to it)

This:

is where it hooks up the gc, boehm, to the allocator code.

This is the code that gets called for “new” (There’s a different one for arrays and delegates under it)

But really from a usage perspective this shouldn’t require anything from you, the gc and the compiler will take care of it. Now if you are allocating large memory blocks and need full control over allocation and freeing there’s always malloc/free (Posix) or ExternalCalls.malloc/ExternalCalls.free (Windows).

The thing with gc vs manual is that both have tradeoffs. The gc does most things in a background thread, it does a minimal amount of “stop of the world” for marking, this is from the boehm description:

Performance of the nonincremental collector is typically competitive with malloc/free implementations. Both space and time overhead are likely to be only slightly higher for programs written for malloc/free (see Detlefs, Dosser and Zorn’s Memory Allocation Costs in Large C and C++ Programs.) For programs allocating primarily very small objects, the collector may be faster; for programs allocating primarily large objects it will be slower. If the collector is used in a multithreaded environment and configured for thread-local allocation, it may in some cases significantly outperform malloc/free allocation in time.

hope that explains it.

Ok, thanks at first for the answer!

But in a more concrete way, im currently designing an own dynamic-array implementation, which is slightly different from the “normal” way:

And currently, im allocating some object-memory like this:

f_root := new Block[initial_length];

When this Code performes, the GC_Malloc(…) takes care of it or more concrete, the RTL
And im freeing it like this:

GC_Free(^Void(f_root));

Is this a relative good way or would you do something different, something more robust/fast ??

Thanks!

just set f_root to nil, GC_Free is not meant to be called. Setting it to nil will (eventually, or we’re low on memory, quite soon) release it.

1 Like

Ok thanks!!

And is this the “only” way or is this the better way on performance perspective or robust-code-perspective?

Not freeing it is more performant yes when using a gc, otherwise it marks it but doesn’t do anything with it. Note that for some types like Streams, there’s the IDisposable pattern to free the underlying resources, but not the memory.

1 Like

Thanks a lot :slight_smile:

When would you actuall say, that an object is large or not?

And how can i configure the GC to be multi threaded-allocation?

I wouldn’t worry about the gc at all to be honest.

That’s already done.

1 Like

To elaborate on Carlo’s answer (and I hope I’m right :wink: ), there is the “using” syntax that will take care of the IDisposable items automatically.

Yes. But IDisposable is completely separate from the GC of course.

Yep. I was responding to your response about the IDisposable earlier.

I don’t really like that IDisposable is separate. I’m guessing there are a lot memory leaky apps out there because of the separation. But that is how it is.

I know when I started doing .net, I didn’t notice that they were separate. And it was a while before I discovered “using”. There are a lot of places where I use the “using” now that seems to make that whole operation safer.

What exactly do you mean by that?

IDisposable is just an interface with 1 method (Dispose). It’s only called if you use a using statement (or if you call it directly). It’s a pattern, not something treated special by the GC.