I asked on the Boehm GC mailing list (if in doubt, ask for help). The conversation starts here.
They provided the following (my summary):
- One benchmark is here, showing that speeds are comparable given sufficient memory (a gc will require more memory) .
- Another is here from Hans Boehm's presentation. See pages 50 onwards. He comments that it is a toy benchmark, on linux.
- Malloc implementations have improved
- Code that favours manual allocation
Simple create, do something, free
- Code that favours gc
Complicated lifetime management
try ... finally, free
Well that kinda helps. But what about in delphi?
I have done some quick tests using my modified version of the delphi wrapper for the Boehm GC (Delphi GC for short). The modifications shouldn't make any major difference to the result.
Delphi benchmark 1:
This is a simple, trivial, benchmark. It creates 60,000,000 small objects and assigns a value.
The object is simply:
and the test is simply
TTestObject = class
destructor Destroy; override;
The try ... finally free section is not required by the GC version as we don't have to worry about memory leaks.
for f := 1 to TestCount do
The GC tests were repeated with a range of initial heap sizes and on different computers. The FastMem test was also tried without the try finally. The source code is available if anyone wants it.
The results are
| ||Old laptop, 512mb||Core 2, 2gig||Single core 2 gig||Quad core 3 gig|
|FMM (no try finally)||approx 31.5|
|FMM try finally||81.281||33.306||37.875||48.046|
Given a large enough initial heap, the gc version ends up faster than the FastMM version.
This is not a serious benchmark, but it does indicate that a gc can be faster than manual allocation.
Delphi benchmark 2
For this, I added the gc to 2 of my existing unit tests. It was a 2 line conversion, I just added the gc and set the initial heap size.
Enable is a work injury management system. It is heavy on database access and single threaded.
Envisage is a document management system. Database access is done via the tiopf object persistence framework. It reads pdf files, checks for bar codes and creates new ones. It is multi-threaded. It uses a large amount of memory.
Here are the results:
|Envisage, no threads||Envisage, threaded||Enable|
Le me restate my conclusion as the initial one is not well worded in terms of what I intended to say. A better conclusion would be "It is possible for a garbage collected application to run at a speed similar to that of an application using manual deallocation". Or alternately, "adding a gc to an application doesn't automatically make it incredibly slow".
The gc performance could probably be improved further by surfacing the gc tuning options, improving the delphi wrapper and using a later version of the GC. The unit tests could also be sped up by removing the now redundant frees, destructors and try ... finally blocks
The Boehm GC used is an early version 6 (6.2 or so). Version 7 is available from cvs. V7.1 should be released soon.
There are downsides to using a gc, such as increased memory use. It is not appropriate for all applications, especially those with memory constraints. However speed does not appear to be one of those downsides.
In response to a query, yes the garbage collector is running, and collecting the objects. After the initial run (which may increase the heap), the heap size remains static no matter how many times I repeat the test (any of the tests).
I also repeated the FastMM test removing the testObj.Free; line.
It "completed" in 35 seconds. By completed, I mean "used up 1.3gig of free mem, all my 4gig page file and then threw an "out of memory" exception.
GC Mailing list: Are there any benchmarks comparing the speed of gc v non gc
Garbage collector for Delphi