discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Garbage Collection


From: David Chisnall
Subject: Garbage Collection
Date: Wed, 25 May 2011 12:47:00 +0100

Hello all of the GNUstep-flavoured people,

After Austin's question, it seems that there is some interest in garbage 
collection, so I thought I'd post a little bit and explain for the benefit of 
people who don't read the commit logs what I've been working on recently:

First, some history.  In the beginning, Objective-C implemented +new and -free 
methods, which wrapped malloc() and free(), and made it impossible to alias 
objects without lots of thought about your objects.  No one liked it, so NeXT 
introduced explicit reference counting with autorelease pools.  This worked in 
every situation except two: If you had cycles in your object graph, you needed 
to be careful that one pointer was not retained (e.g. the reference of a view 
to its delegate).  If you made a mistake anywhere, then you'd get a crash - 
probably some time after your actual bug.  

Some time not much later, GNUstep added support for garbage collection using 
the Boehm collector.  This required some significant changes to the source, and 
the legacy of this is a load of #ifdef GS_WITH_GC lines littered about the 
source.  As far as I know, this was never actually used by anyone beyond some 
demos, and didn't work properly with GUI applications[1].  

There were also some limitations with the GNUstep approach - aside from needing 
programmer effort, which somehow defeats the point of GC.  The lack of weak 
references meant that some common patterns caused memory leaks.  For example, 
in the traditional retain/release world, an object registers itself with 
NSNotificationCenter, which holds an unretained pointer to it, and then 
unregisters itself in -dealloc, when it is no longer referenced by anything 
else.  In a garbage collected world, NSNotificationCenter has a reference to 
the object, so it will never be freed, so can not unregister itself.  The 
notification center requires a weak reference, so that the object can be freed 
when nothing else holds a reference to it and the notification centre can then 
clean up.

With OS X 10.5, Apple introduced their own way of doing garbage collection.  
This had the compiler insert read and write barriers for weak references, and 
write barriers for strong references.  This was, of course, completely 
incompatible with the GNUstep approach (NIH is strong at Apple).

Over the past few days, I have been working to implement Apple's solution in 
clang and the GNUstep runtime.  This required about 500 lines of new code in 
the runtime, some tweaks in clang (mainly because someone at Apple had decided 
that no platforms other than Darwin supported GC, so the front end was 
rejecting the -fobjc-gc options, even though they mostly worked).  In -base, 
there were very few changes outside of NSZone and NSObject.  I have made no 
changes at all in -gui, and one minor change in -back (turning malloc() into 
NSAllocateCollectable() for some structs that contain pointers).

If you are using trunk versions of the runtime, clang, base, and back, 
Apple-compatible garbage collection now works well enough for Gorm to run.  It 
appears to use marginally less memory than in manual retain / release mode 
(most likely due to some autoreleased objects being held in the top-level 
autorelease pool).

Apple supports two options: -fobjc-gc, which is intended for frameworks that 
support both garbage collection and manual reference counting modes, and 
-fobjc-gc-only, which does not permit linking against non-GC code.  I have some 
preliminary code that supports -fobjc-gc, but it's a bit messy and I'm not sure 
it's worth bothering with (anyone have an opinion?  Is this actually a useful 
feature), but -fobjc-gc-only works quite well (well enough for Gorm, anyway - 
I've not done extensive testing).

To use this, all you need to do is compile the runtime with boehm_gc=yes and 
add -fobic-gc-only to your OBJCFLAGS everywhere else.  Please let me know if 
you find anything that breaks.  Currently there is one thing that I know 
doesn't work:

Because -retain messages are omitted in GC mode, blocks will not be copied if 
sent a -retain message.  Holding a reference to a block requires an explicit 
Block_copy().  I'm not sure the best way to address this (or what Apple does, 
in fact).  I can probably fudge it slightly with a really ugly hack that checks 
whether the isa pointer of an assigned object is a block, but that's a bit of a 
kludge).

Please test, please use, please let me know how performance is affected,

David

P.S. The only change to the ABI currently is bumping the module version 
(causing old runtimes that don't support GC to reject modules that expect it) 
and adding a flag to the module indicating the GC mode (none / optional / 
required).  This is currently experimental code (neither the compiler nor the 
runtime has had an official release with GC support enabled), and is subject to 
change, so now is a good time to provide any feedback.  Since GC-only code is 
incompatible with retain/release code, we get to break the ABI completely, so 
now is a good time for feature requests for the new ABI...

[1] I've never actually tried - it's entirely possible that it did, but I was 
told that it didn't.

-- Sent from my brain


reply via email to

[Prev in Thread] Current Thread [Next in Thread]