Using JUCE with the BOEHM garbage collector


#1

Julian,

one of my planned tasks soon is to get my JUCE Apps working with the BOEHM garbage collector. This is necessary because my JUCE Apps are originally written in REALbasic, which has its own ( reference based ) built-in memory management. I then use my in-house REALbasic > C++ conversion tool to create a C++ version which uses the JUCE framework to emulate a subset of the REALbasic framework.

Do you foresee any major problems with this ? I realise JUCE provides quite a lot of classes that handle memory management, reference based. Do you think there will be any clash ?.

And if not, would the addition of an option to use BOEHM in JUCE apps be a feature worth adding ?

One of the main reasons i like the BOEHM GC method is it avoids the hassles of circular references that occurs in reference based gc schemes, weakrefs help of course but the whole thing is a pain.

Dan


#2

I’ve never used the boehm collector myself - how does it handle object destructors? Does it call them? If so, what thread does it use?


#3

its a few years since i was working with BOEHM ( on my project ) but to my recollection the collector includes its own memory allocator. and has code to override the C++ new, delete keywords and has its own implementations for malloc etc. to my recollection it also allowed for an option to use a specific “base” C++ class to assist GC operation but i believe this isn’t at all mandatory. At heart this is a C based collector, not reliant on C++ at all.

i believe It doesn’t call any destructors itself , it scan around for ptr size data that points to any of the allocated memory blocks in the heap, and if it finds no data that could be a pointer to the block in question considers it “unreachable” and marks it for deletion. this is all done i believe in separate threads or when explicitly called.

I can give you more of an update later once i begin again in earnest.

I actually did have BOEHM linked into my JUCE project a gew yrs ago, but decided to comment out the code due to problems debugging it, and chose to just get my JUCE app prototype going, while just ignoring the obvious memory leaks. Now i need to see if i can put the boehm code back.


#4

Ah, well if destructors don’t get called, then you’d have to be careful not to allow any juce objects to be garbage-collected, otherwise there could be resource leaks. E.g. if you created a FileOutputStream, and let it get collected, it’d leave the file handle open.


#5

im pretty sure destructors still get called, ill check that. i seem to recall there was some C++ code to handle that.


#6

…but if they do get destroyed, what thread would do the deletion? Very few object destructors are designed so that they can be safely called from any thread…


#7

agreed. a

And i think i was probably wrong about the thread thing. I’m in great danger of just talking out of my *rse if i carry on, so I’m going to look back at the BOEHM code later tonight to remind myself of the whole thing, or tomorrow and clarify things properly.

Basically for me - i need to decide once and for all to shoehorn BOEHM into JUCE if feasible, or i will need to adopt the JUCE memory management features, obviously based around reference counting. Which will involve me having to go back to REALbasic code and remove any circular references using weakerefs etc etc , which will of course be entire tedium.

My hope is that - at most - maybe a few minor additions/alterations to JUCE might suffice, or none are needed at all - but i may be wrong…


#8

Boehm use a technic called “sweep space”.
Basically, at regular interval on invokation (malloc / free), it scans the heap for pointers and compute a kind of ref count on them. If they are not used anymore, it simply delete them.
For C++, it’s a bit smart, because it stores the pointer to the “deleting” function, likely a destructor so yes it does call destructors.

However, there is no more the “destructor time ordered” cleaning (for example, if you don’t delete a FileOutputStream, the file will be closed at whatever time Boehm want, and you can have your application trying to open the file again while it’s still not flush nor deleted and this results in subtle bugs), so this is a bit dangerous to use on existing code, you have to design your own application differently if you use a GC.


#9

Hi x-Ry1669,

regarding "for example, if you don’t delete a FileOutputStream, the file will be closed at whatever time Boehm want”:

Are you saying BOEHM doesnt ? call the C++ destructor BEFORE it frees the memory for an object ? I thought BOEHM only begins the collection process on an object instance once it determines that NOTHING is pointing to the
object in question. Surely in the example you gave BOEHM would NOT be able to close the File linked to the FileOutputStream because as long as the FileOutputStream instance exists it will be holding its own pointer somewhere to the File.

This of course brings up the possibility of circular references via pointers preventing the GC from collecting such paired objects - but i thought this problem was exactly what BOEHM was meant to solve. I must be getting confused abut boehm. Again - i need to look into this more in anger when i have time.


#10

No. Boehm always does call the destructor before freeing the memory. However, it doesn’t do it WHEN you expect it, but only when it is elected to run (that is, on the next new/malloc/free/delete call), and even that isn’t deterministic.
For example, if you have a thread 1 doing:

thread1
{
    FileOutputStream * stream = ...
    stream->write(something);
    syncEvent.signal();
}

thread2
{
    syncEvent.wait();
    FileInputStream * stream = ... same file ...
    stream->read() // expecting something, won't get it, since Boehm might not have collected it yet, so the FileOutputStream destructor isn't called, and the flush and close on the file is not done yet.
}