Does System.gc() need a pause ?

i often see some code snippets for manually cleaning up memory like:


System.gc();
try
{
    Thread.sleep(500);
}
catch(InterruptedException e){ ... }

// or 

System.gc()
Thread.yield();

its used for giving the garbage collection request some amount of “free time” so that it is really invoked.
but does this really have any affect ? or is the gc request so independent that it follows it own rules ?

It’s pretty pointless really.

Cas :slight_smile:

good to know. would have been a little wired though.
but i am really sure to have read this in a java game book. i only have to look up if it was the one from brackeen or petchel … 8)

That’s actually a left-over trick from the 1.1 days. Back then the Garbage Collector would happily interrupt your game at the worst time possible. As a result, programmers got used to manually invoking it when they knew their program had a little extra time to burn.

These days, that trick actually slows down the JVM. The Garbage Collector is a far more complex device than the mark and sweep collector of Java 1.1, and is quite good at keeping itself out of the way.

The trick is still useful with MIDP many times (though device-dependantly).

shmoove

ohh good to know shmoove. its exactly for j2me purposes, though i thought its a general purpose, i didnt post it there.
some overview, where to use it and where to avoid ?

[quote]That’s actually a left-over trick from the 1.1 days. Back then the Garbage Collector would happily interrupt your game at the worst time possible. As a result, programmers got used to manually invoking it when they knew their program had a little extra time to burn.

These days, that trick actually slows down the JVM. The Garbage Collector is a far more complex device than the mark and sweep collector of Java 1.1, and is quite good at keeping itself out of the way.
[/quote]
But then still, why the extra sleep?
It seems pointless, even for 1.1

[quote]But then still, why the extra sleep?
It seems pointless, even for 1.1
[/quote]
The sleep was usually a calculated time period, not a fixed one. However, fixed time periods were not uncommon. Since the mark and sweep collector would make the same pass each time, you could get fairly consistent timing for each loop. Just tune your sleep time correctly, and your framerate should naturally fall about where you want it.

Truth be told, though, I think that slowness was an advantage for 1.1. Since your code couldn’t produce more than 15-30 FPS anyway, you could run flat out and never even care about timing. :slight_smile:

It seems to me the sleep has a different purpose and has nothing to do with GC then… :-/

[quote]ohh good to know shmoove. its exactly for j2me purposes, though i thought its a general purpose, i didnt post it there.
some overview, where to use it and where to avoid ?
[/quote]
Well, you have to take it in a case by case basis. Off the top of my head, I can tell you about some SKVM devices (A Korean flavour of J2ME) that need to have code like that (gc then sleep) after every time a network connection attepmt failed, or else you would never be able to make another successful connection.
Nothing can be generalized because this trick is usually used to overcome various bugs in the implementations.

[quote]It’s pretty pointless really.
Cas :slight_smile:
[/quote]
You sure about it?
My fastest arithmetic compressor used 400 MB RAM of 500 MB, then threw it away, then alocated another 400 MB. It swaped pretty heavily without System.gc().
Of course a little swaping isn’t bad, but 400 MB swaping * 2 is nasty even on lastest (non flash) HD.

I did a pretty nice example of GC work, but it get lost when I pressed post button, so GC internal isues are left to imagination of programmer.

Should have set your memory usage parameters before running it then :wink:

Cas :slight_smile:

I did that. I set “don’t use more than xxxx nodes”. It used them, threw them away, and used another xxxx nodes. Just GC didn’t reacted quickly enough.

Yes these are the problems when you have fastest arithmetic compressor in the world, GC isn’t fast enought. ~_^

The GC reacts “on-demand”. You make a request, there’s not enough space, it clears some garbage away. You gain incredible speed in allocation versus an occasional pause on a new().

Cas :slight_smile:

Yes that’s the theory.
The problem is when you’d have container = new container(hold rest of the 30000 nodes);
Then somewhere else container = new container(hold rest of the another 30000 nodes);

So you are in situation when first 30000 nodes and container isn’t garbage collected, but other container is quickly filled, for example by 30 nodes per byte of compressed data. Result? Old container isn’t valid, all refferences for old nodes in the container aren’t valid either. GC would have two options. 1. alocate another memory that would be taken from the swap. 2. look throught all refferences for one null one, then look again for rest of the null ones.
From my experience it would take the first aproach, throught best generic aproach would be a combination of the two above options.

null the reference to the first container?

Cas :slight_smile:

I expect when you have code like this

 for( int c1 = 0; c1< files.length; c1++){
   container  someContainer = new container(150000);
}

writing someContainer = null is no help.
It might be interesting to send from various parts of the code hints to GC like
GC.hint(GC.TIME_AVAILABLE, 3000);
GC.hint(GC.CLEAN, GC.ALL);
GC.hint(GC.CLEAN, GC.LAST_FRAME, 0); //translated data allocated between two calls GC.hint with identifier 0 .

Programmatic GC hinting is a really important feature, and it’s very surprising we’ve still only got System.gc() after all these years.

Cas :slight_smile: