direct buffers and garbage collection

M

Mike

The following code fails with OutOfMemoryError


Code:
final int SIZE = 15000;
int N = 500000;

long start = System.currentTimeMillis();

for (int i = 0; i < N*5; i++) {
ByteBuffer buf1 = ByteBuffer.allocateDirect(SIZE);
//            System.gc();
}
long timeHeap = System.currentTimeMillis() - start;

but if I uncomment System.gc() call, everything "works".

Yes, I am aware that direct buffer is allocated in system memory. But
still, why isn't garbage collector automatically called, when there is
no more "system" memory available? Since there is no direct way to
"disallocate" direct buffer, it should be.

What is that, a bug? :(

P.S.
jdk 1.4.1_05-b4
Windows XP Prof
512Mb RAM
 
C

Chris Uppal

Mike said:
The following code fails with OutOfMemoryError


Code:
final int SIZE = 15000;
int N = 500000;

long start = System.currentTimeMillis();

for (int i = 0; i < N*5; i++) {
ByteBuffer buf1 = ByteBuffer.allocateDirect(SIZE);
//            System.gc();
}
long timeHeap = System.currentTimeMillis() - start;

but if I uncomment System.gc() call, everything "works".

Yes, I am aware that direct buffer is allocated in system memory. But
still, why isn't garbage collector automatically called, when there is
no more "system" memory available? Since there is no direct way to
"disallocate" direct buffer, it should be.

I can think of two possibilities, but I don't know which (if either) is
relevant here.

I'm presuming that the result of ByteBuffer.allocateDirect() is a
DirectByteBuffer containing a reference to "system memory" that is released by
finalisation.

One possibility is that the loop runs and generates lots of garbage, /but/ the
system never runs out of "normal" memory to allocate objects in and so never
schedules a garbage collection and in turn never does any finalisation. This
is a basic problem with using finalisation to manage /any/ resource that is
more scarce than normal object memory. It is possible to alleviate the problem
by ensuring that the attempt to create a new instance of the scare resource
will do a GC() if the attempt fails. The problem with that is that it assumes
there is an interface for asking for a GC and finalisation to run and complete
before returning. Java, unfortunately lacks such an interface, although
system.gc() might do the necessary in some particular implementations. In
fact, the DirectByteBuffer appears (to a casual glance) not to do that.

Another possibility is that the GC has been running normally, and that lots of
"garbage" DirectByteBuffers have been identified and queued for finalisation.
(So they are not technically garbage at all, yet). If the finaliser is running
on a separate thread (the typical case) then it may not be scheduled fast
enough or often enough to keep up with the rate that you main loop (with which
it is competing for CPU time) is comsuming system resources.

The real problem here is that NIO presents no way to clean up a
[Direct]ByteBuffer /except/ relying on finalization, and that is not so much a
bug as a serious design error.

-- chris
 
A

ak

for (int i = 0; i < N*5; i++) {
ByteBuffer buf1 = ByteBuffer.allocateDirect(SIZE);
// System.gc();
}
Buffer(s) are intended to reuse it.
aspecialy direct buffes.
So don't create every time new buffer.

DirectBuffer cannot be relocated by GC.
May be this is your problem - you have anough memory,
but it is segmented ==> VM can't allocate ==>OutOfMemoryError.
 
M

Mike

JavaDoc for OutOfMemoryError says that garbage collector is asked to
gc() and only if it can't free up enough memory exception is thrown.
Direct buffers are indeed allocated in "system memory". Seems like
for whatever reason (most likely because "system memory" is not taken
into account) garbage collector isn't called by the system before
throwing OutOfMemoryError (since it sees there is a lot of "normal
memory" so there is no reason to gc()).

I think this can be considered a bug.
 
K

Kevin McMurtrie

The following code fails with OutOfMemoryError


Code:
final int SIZE = 15000;
int N = 500000;

long start = System.currentTimeMillis();

for (int i = 0; i < N*5; i++) {
ByteBuffer buf1 = ByteBuffer.allocateDirect(SIZE);
//            System.gc();
}
long timeHeap = System.currentTimeMillis() - start;

but if I uncomment System.gc() call, everything "works".

Yes, I am aware that direct buffer is allocated in system memory. But
still, why isn't garbage collector automatically called, when there is
no more "system" memory available? Since there is no direct way to
"disallocate" direct buffer, it should be.

What is that, a bug? :(

P.S.
jdk 1.4.1_05-b4
Windows XP Prof
512Mb RAM

There are probably several issues related to asynchronous garbage
collection.

- Some VMs default to using the Concurrent Mark and Sweep Collector, or
variations of, it when low-overhead threading is available. Concurrent
collectors take a while to run but most of the work doesn't interrupt
program execution. I've tested this collector a bit and it behaves very
badly when allocations outpace collection.

- Heap aging is rather delicate and poorly functioning by default.
Self-tuning sometimes results in self-destruction. Turn on all the GC
messages to see if you need to tweak the New Heap (Eden) size and
tenuring parameters.

- You have to remember that collection is pipelined. Objects must be
found by the GC, put in the Finalizer queue, finalized, found again by
the GC as still being free, References must be tidied, and then memory
may be released. Usually the finalizer thread runs very rapidly but it
can become backlogged if finalize() methods or References result in
blocking I/O. It's very possible that the NIO buffer's finalize()
method blocks on a context switch or VM swap.

Your sample code might run if you change the garbage collector and tweak
some environment variables. The GC has been so optimized for bandwidth
and multi-threading that you can't expect any specific behavior from it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,023
Latest member
websitedesig25

Latest Threads

Top