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 _______________________________________________ Discuss-gnustep mailing list [email protected] https://lists.gnu.org/mailman/listinfo/discuss-gnustep
