performance problems

Jeff Sturm jsturm@sigma6.com
Mon Aug 16 08:07:00 GMT 1999


Norman Hendrich wrote:
> On the weekend, I finally had some spare-time to run some more tests.
> While some simple apps show good performance (see below), memory-intensive
> apps still show the factor-of-five-slowdown I reported last week.
> As others don't see this behaviour, my Linux configuration is probably
> broken somewhere...

A couple of things...

First, you don't say how much memory you have installed, or how large
the process grows.  Is there any chance of swapping during the tests?

Second, what heap parameters are you passing to the JDK?  As I mentioned
earlier in this thread, memory-intensive code can benefit from a large
initial heap.  The current libgcj has no mechanism for specifying the
initial heap size, however, so if you are using a large -ms value it
isn't a fair comparison.

Earlier I wrote a small program to allocate 1,000,000 objects (16-byte
arrays, actually) and measure the runtime duration and heap usage.  I
tried it with both the IBM JDK 1.1.6 and the gcj-2.95 release:


[jsturm@toronto jsturm]$ javac -O T.java
[jsturm@toronto jsturm]$ java T
java.lang.OutOfMemoryError
        at T.main(Compiled Code)
[jsturm@toronto jsturm]$ java -mx64m T
complete in 10595 ms
total memory = 37576695
free memory  = 1201600
[jsturm@toronto jsturm]$ java -ms64m -mx64m T
complete in 1507 ms
total memory = 67108855
free memory  = 30437655
[jsturm@toronto jsturm]$ gcj -O3 T.java --main=T -o t
[jsturm@toronto jsturm]$ ./t
complete in 6175 ms
total memory = 37007360
free memory  = 36306944
[jsturm@toronto jsturm]$ export GCJ_HEAP_INIT=67108864
[jsturm@toronto jsturm]$ ./t
complete in 4352 ms
total memory = 67174400
free memory  = 36294656

Both the JDK and libgcj benefit from a large initial heap, although the
difference is far smaller in libgcj.  (The GCJ_HEAP_INIT variable was a
local hack and does not work with the libgcj-2.95 release.)  The JDK
also appears to use more heap, assuming Runtime.freeMemory() isn't bogus
(note the third result above looks suspicious).  I expected a little
more heap consumption from the JDK since it's collector is based on
handles, and the Boehm GC isn't.

Comparing the 2nd and 3rd results shows a factor of four, which could be
similar to what you're observing.  Overall the Boehm allocator works
well... sometimes it's faster than the JDK, sometimes slower.  I like
the algorithm it uses to avoid fragmentation... though it probably incur
somewhat higher allocation costs, avoiding the heap compaction is a big
win.

I'm not sure whether a GC cycle took place during any of the tests,
which could have a big impact on the results.  (It'd be really nice to
have a way to profile GC activity in libgcj, much like -verbosegc does
for the JDK.)

Here's the code to produce the results above:

public class T {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        Object[][] array = new Object[1000][];

        for (int i = 0; i < 1000; i++) {
            //System.out.println(i);

            array[i] = new Object[1000];

            for (int j = 0; j < 1000; j++) {
                array[i][j] = new byte[16];
            }
        }

        long end = System.currentTimeMillis();

        System.out.println("complete in " +
            (end - start) + " ms");
        System.out.println("total memory = " +
            Runtime.getRuntime().totalMemory());
        System.out.println("free memory  = " +
            Runtime.getRuntime().freeMemory());
    }
}

> gandalf> time ./a.out 100000
> Shellsort self test started...
> ...generating random numbers...
> ...sorting...
> ...checking...
> ok.
> 6.890u 0.050s 0:13.68 50.7%     0+0k 0+0io 456pf+0w
> 
> Note that the total runtime of the app is double the reported user-time
> (the runtime is a little longer because this time I didn't use the -O3 flag).
> It seems that the gcj code always forks a second process (is this the
> garbage-collector?) which on my system uses as much CPU as it can get -
> in this example, 50%. Is this GC behaviour normal?

libgcj doesn't normally fork processes.  On Linux, individual threads
show up as separate entries in the process table (and thus in /bin/ps)
even though they belong to the same process.

GC in libgcj always runs in foreground, I think...

Is your code multithreaded by any chance?

-- 
Jeff Sturm
jsturm@sigma6.com


More information about the Java mailing list