Memory Handling

General help with the eC language.
Post Reply
fedor_bel
Posts: 21
Joined: Sun Mar 14, 2010 4:46 pm

Memory Handling

Post by fedor_bel »

Dear Jerome,

What is the memory handling strategy in Ecere?
I am a bit confused, because I can not program as easily as in Java, without worrying about memory management at all.
Maybe you could formalize some memory handling programming Patterns to adapt to when using Ecere?
Right now I am using a mixture of old scurpulous memory considerations as it was in C/C++, but at the same time subconsiously willing to program good old Java style.
I have studied your beautiful Samples, trying to learn the programming patterns you use in relation to memory handling.
But even now I find myself always thinking on a dilemma of how to program: memory careless or careful?
fedor_bel
Posts: 21
Joined: Sun Mar 14, 2010 4:46 pm

Re: Memory Handling

Post by fedor_bel »

Hello,

I tryed to write a self-made simple garbage collector, that keeps track of all local variables holding pointers to objects allocated on the heap. In the garbage collector run I then check that those variables still point to the same address, and if the count of variables, pointing to the watched address is equal zero - i free the heap memory at that address.

It worked pretty well for some first time, but then in my garbage collector I suddenly could not access some stack variables, why can that be? Maybe the reason is the garbage collector runs in a separate thread? It can access stack addresses from the main program thread (from which the garbage collector thread was started), but seem to fail to access stack addresses of other threads, created aftewards.
jerome
Site Admin
Posts: 608
Joined: Sat Jan 16, 2010 11:16 pm

Re: Memory Handling

Post by jerome »

Dear fedor,

eC provides some tools to simplify memory management.

However it doesn't take care of it all for you, so you can't be careless.

First, it is important to understand exactly what memory eC manages for you...

Instances of classes (Either those declared as 'class MyClass { }', and those declared as class MyClass : struct { }) are always allocated on the heap. These objects, when either declared globally, or as instance members of other objects, are automatically freed (For the former case, when a module (dynamic library / executable) is unloaded; for the latter case when the object containing it is destroyed).

There are plans to extend this behavior as well to all instantiations of those objects, that is to add this behavior to local function variables. This is not yet implemented in the compiler.

Additionally, regular classes (those declared as 'class MyClass { }') feature a 'reference counter'.
The reference counter however is not automatically incremented/decremented.
Calling 'delete' effectively decrements the reference counter by 1, and if it is <= 0, the instance gets deleted. One can use 'incref object;' to increment by one the reference count.

Global and member instances (Those that get automatically freed, as explained above) will start with a reference count of 1, and they get decremented by 1 at the module unload / parent object destruction.

Local function variables currently start with a reference count of 0, this would change to 1 when we implement the functionality as explained above. Anonymous instantiations (e.g. MyClass object; object = MyClass { }) also start with a reference count of 0.

Headerless classes (those declared as 'class MyClass : struct) do not have a reference counter so doing a delete automatically invokes the destruction of the object.

Structs ( struct MyStruct { } ) are always allocated 'in place', they will never be allocated on the heap except for when they are a member of a class, or when explicitly allocated with the new operator.

Additionally, some classes defined in the Ecere library will be managed by the runtime, that is the runtime will hold on a reference count. Some examples of this are Windows (and thus all dialogs and common controls) and Sockets. This typically means one does not need to worry about deleting these objects.

To sum it up, here are a few guideline rules:

- If you allocate memory with new, you need to free it with delete. Just like you need to call free() when you call malloc() in C.
- Except for the above rule, struct objects never need to be deleted.

- Local (inside functions) class instances need to be deleted. This might no longer be the case in a future version of eC.
- Anonymous instantiations need to be deleted.
- An exception to the 2 above rules is made for objects that are self managed (like Windows and Sockets): the system will delete them for you when they are no longer in use.


In general, you should find that these memory managing patterns work out pretty good. Not a lot of memory management is left for you to do, yet you still have full control over when memory is allocated and freed, and no garbage collection overhead. That is the strategy.

Cheers,

Jerome
jerome
Site Admin
Posts: 608
Joined: Sat Jan 16, 2010 11:16 pm

Re: Memory Handling

Post by jerome »

Hi fedor,

The idea of a 'thread' is that each thread has its own stack.

That's how you can be in different functions in each thread, all function local variables are allocated on that stack.

My suggestion is that if you just follow the guidelines I just outlined, you should find things to go smoothly enough... Please don't hesitate to comment or ask advice about these rules or any specific scenario you are trying to decide on how to manage memory.

Cheers,

Jerome
Post Reply