The short version of the story - By setting gc=false and adding the following parameter to the VM command line" -XX:+AggressiveHeap, ECJ used 28% less computational time. Same seed. The performance increase is a result of instructing the JVM to use a more efficient garbage collection algorithm. Note, using this switch uses memory more aggressively, so you may want to read on. The long version of the story. I have been using ECJ for the last year and in the past few months became interested in increasing performance. To that end, I added timers to each of the major operations of ECJ. Here's what a typical report my look like: > Java Default GC Parameters > > Run Time:93.94 -> 100.00% > Setup:3.98 -> 4.23% > Evaluate:17.94 -> 19.09% > PostEval Stats:4.32 -> 4.60% > Breed:67.02 -> 71.34% > Final Stats:0.90 -> 0.96% First number is seconds and second number is percent of CPU time. I was surprised to see that breeding consumed such a large proportion of the CPU consumption - 71%. Timers were added to specific functions inside of breeding: > Run Time:93.94 -> 100.00% > Setup:3.98 -> 4.23% > Evaluate:17.94 -> 19.09% > PostEval Stats:4.32 -> 4.60% > Breed:67.02 -> 71.34% > --PrepareToProduce:7.47 -> 7.95% > --Produce:59.38 -> 63.21% > ----Produce_BreedingSources:0.78 -> 0.83% > ----Produce_Produce:57.95 -> 61.68% > ------CrossOverPipeline_Breed6:33.62 -> 35.79% > -------CrossOverPipeline_Breed7_childAllocate:8.02 -> 8.54% > Final Stats:0.90 -> 0.96% One line of code “obj.children = new GPNode[children.length]” was found to consume 8.54% of the CPU time. This line of code allocates memory from the heap for tree children - a very common operation in breeding. A first tack against this consumer was to think that dynamic object allocation was eating processor time. This could be cured by statically defining a collection of nodes that the GP could recycle through without JVM memory allocation/de-allocation. This was briefly explored until realizing that creating/maintaining such a collection would require extensive code changes. A second and ultimately successful tack was to consider the de-allocation side. Was the JVM’s garbage collection consuming the processor time? Garbage collection is performed by the JVM without needing to be programmed directly – one of the beauties of Java – no memory leaks. In most programs, this does not introduce performance degradation. However, most programs don’t allocate millions of objects per second as ECJ. While Sun Java does offer some access to performing explicit garbage collection in code, doing this in ECJ only introduced additional performance degradation. The other way to control GC is through JVM command line parameters. After a bit of internet research, the following command GC/Heap parameters were discovered and tested. > 75000 individuls x 5gen > Command Line Switch Total Run Time > --none-- 11.5s > -XX:+UseParallelGC 13.7s > -XX:+UseConcMarkSweepGC 16.5s > -Xincgc 16.7s > -XX:+UseAdaptiveSizePolicy 11.6s > -XX:+AggressiveHeap 7.2s After determining the best command line switch, I tested combinations of ECJ's garabge collection and the switch. > 75000 inds x 50gen – testing switch with ECJ code GC > Command Line Switch ECJ GC Total Run Time > --none-- none 93.9s > -XX:+AggressiveHeap none 62.0s > --none-- normal 100.1s > -XX:+AggressiveHeap normal 78.8s > -none aggreesive 111.2s > -XX:+AggressiveHeap aggressive 91.0s As can be observed from the above results, using -XX:+AggressiveHeap and turning off ECJ GC resulted in the much fastred run times by far. A note on memory usage. -XX:+AggressiveHeap is just that - aggressive. If you get an "Out of Heap Memory" error when using this switch, then you will need to setthe VM parameter Xmx???m. This parameter sets the maximum heap size and units are megabytes. The smallest value I ever use is: Xmx75m. I'm running symbolic regression with average trees sizes of 18. My rule of thumb is to allocate 2M of memory for every 1,000 individuals. For example, a run of 200,000 individuals, I will set the parameter to Xmx400m. Your needs may be more or less depending on your tree/population sizes. There's a balance here. It needs to be set high enough so there's enough heap space. It needs to be set low enough as to not aggressively consume so much memory that you start doing disk page swaps, especially if you're running multiple simultaneous runs. Again, this might not be an issue for smaller populations, non-paralell runs or if you have vast amounts of memory. For more information on the -XX:+AggressiveHeap switch and other heap related switches: http://java.sun.com/j2se/1.4.2/reference/whitepapers/ I'd love to hear back from any of you who experiment with this. Also, if there's popular demand, I can include the Performance Monitoring Class that I've created. best initentions, Chris Ellingwood (University of Vermont, Botany) ----------- Configuration I: Sun Java: 1.5.0_05 Dual Processor Xeon 3.6 GHZ Windows XP - 64 bit ECJ 11 Configuration II: Sun Java: 1.5.0_05 Pentium 4 - 2.4 GHZ Windows XP ECJ 11