Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

calling System.gc to suggest garbage collection

1 view
Skip to first unread message

Roedy Green

unread,
Nov 26, 2009, 2:36:20 AM11/26/09
to
The general advice we tend to give is don't use System.gc. Just let
the system do its thing. Further, calling it does not FORCE garbage
collection, just suggests it may be a good time for it.

Are there any exceptions to this general rule?

e.g. when you know the system will likely be idle for a while.

when you know the number of live objects is at a minimum just now.
--
Roedy Green Canadian Mind Products
http://mindprod.com
I mean the word proof not in the sense of the lawyers, who set two half proofs equal to a whole one, but in the sense of a mathematician, where half proof = 0, and it is demanded for proof that every doubt becomes impossible.
~ Carl Friedrich Gauss

markspace

unread,
Nov 26, 2009, 9:52:37 AM11/26/09
to
Roedy Green wrote:
> The general advice we tend to give is don't use System.gc. Just let
> the system do its thing. Further, calling it does not FORCE garbage
> collection, just suggests it may be a good time for it.
>
> Are there any exceptions to this general rule?
>
> e.g. when you know the system will likely be idle for a while.
>
> when you know the number of live objects is at a minimum just now.


I would say: after careful user testing. Not just profiling but
actually observing how users really interact with the system. Then
consider some judicious use of System.gc() *if* you can justify results.

Do some A-B testing with versions of the system with System.gc() and
without. If there isn't a clear increase in users' satisfaction it's
not worth it.

Also: use other GCs (specify them on the command line or in the Jar
manifest) and change around the parameters for each GC too, first,
before modifying the code. System.gc() is a last resort only.

Note: I've never gone through these steps myself. Idle speculation only.

rossum

unread,
Nov 26, 2009, 11:14:55 AM11/26/09
to
On Wed, 25 Nov 2009 23:36:20 -0800, Roedy Green
<see_w...@mindprod.com.invalid> wrote:

>The general advice we tend to give is don't use System.gc. Just let
>the system do its thing. Further, calling it does not FORCE garbage
>collection, just suggests it may be a good time for it.
>
>Are there any exceptions to this general rule?
>
>e.g. when you know the system will likely be idle for a while.
>
>when you know the number of live objects is at a minimum just now.

I would possibly call gc just before creating a very large in-memory
structure after the program has been runing for some time, in order to
defragment the heap as much as possible.

rossum

Daniel Pitts

unread,
Nov 26, 2009, 1:52:18 PM11/26/09
to
Roedy Green wrote:
> The general advice we tend to give is don't use System.gc. Just let
> the system do its thing. Further, calling it does not FORCE garbage
> collection, just suggests it may be a good time for it.
>
> Are there any exceptions to this general rule?
>
> e.g. when you know the system will likely be idle for a while.
>
> when you know the number of live objects is at a minimum just now.
I like the we IntelliJ handles this. There is a button that the user can
press if they feel like calling gc. the "widget" in question also
displays memory stats (current heap allocation and size). Its just too
bad that Java doesn't have any mechanism to report the progress of the
current garbage collection cycle.

Actually, the more I deal with Windows, the more I think GC time is
taken up by a lot of "thrashing", because Windows swaps out the less
frequently used memory, and Java "explores" that memory to determine
whether to collect it or not.

I wonder if there could be some sort of algorithm that is
virtual-memory-swap aware.

Thomas Pornin

unread,
Nov 26, 2009, 2:23:08 PM11/26/09
to
According to Daniel Pitts <newsgroup....@virtualinfinity.net>:

> I wonder if there could be some sort of algorithm that is
> virtual-memory-swap aware.

There are such algorithms and Java actually uses some of them. If
not, situation would be _much worse_ when hitting swap. But it is
a really complex issue.


--Thomas Pornin

Peter Duniho

unread,
Nov 26, 2009, 2:27:09 PM11/26/09
to
Daniel Pitts wrote:
> [...]

> Actually, the more I deal with Windows, the more I think GC time is
> taken up by a lot of "thrashing", because Windows swaps out the less
> frequently used memory, and Java "explores" that memory to determine
> whether to collect it or not.

That would be an issue on any OS with virtual memory management.
Swapping out least-recently-used pages is a fundamental approach to VMM.
Anything that then later intentionally touches all those LRU pages
(e.g. a GC pass) causes them to swap back in.

That said, I would expect disk thrashing to occur only in
RAM-constrained scenarios. VMM's (including Windows) don't generally
aggressively swap out memory pages, so as long as there aren't other
processes that need the physical RAM at the same time your Java program
is running, the Java heap should remain paged-in.

> I wonder if there could be some sort of algorithm that is
> virtual-memory-swap aware.

I suppose one could change the GC to touch the heap objects _more_ in
hopes of keeping them paged in. But I believe that would be
counter-productive, because if there are other processes that also have
legitimate need to use memory, that would just increase the contention
for physical RAM.

To the extent that a smaller working set reduces paging, anything Java
can do to reduce the amount of memory it actually accesses would be
productive. But that is already a basic goal, even ignoring
page-swapping issues. GC is more costly the more objects that need to
be inspected, even if all those objects are already swapped-in.

And in fact, the Java GC implementation has features intended to address
that goal of reducing memory accesses (e.g. object generations).
Inasmuch as Java already does what it can to reduce the number of
objects it has to inspect during a GC pass, it thus also is already
doing what it can to reduce the active working set, reducing page swapping.

Whether that qualifies in your mind as "virtual-memory-swap aware", I'm
not sure. But I think it's safe to say that the Sun developers who are
responsible for the JVM and its memory management implementation fully
expect Java to be running on systems with virtual memory management and
a swap file, and do take that into account to the extent that they can.

Pete

Lew

unread,
Nov 26, 2009, 9:06:12 PM11/26/09
to
Peter Duniho wrote:
> To the extent that a smaller working set reduces paging, anything Java
> can do to reduce the amount of memory it actually accesses would be
> productive. But that is already a basic goal, even ignoring
> page-swapping issues. GC is more costly the more objects that need to
> be inspected, even if all those objects are already swapped-in.
>
> And in fact, the Java GC implementation has features intended to address
> that goal of reducing memory accesses (e.g. object generations).

Young-generation collections don't touch dead objects.

<http://www.ibm.com/developerworks/library/j-jtp01274.html>
"copying collectors do not visit dead objects, a heap with a large number of
temporary objects, which is a common situation in Java applications, costs
very little to collect; simply trace and copy the live objects to a survivor
space and reclaim the entire heap in one fell swoop."

The same article discusses why one should *not* call 'System.gc()':
"... developers often mistakenly think they are helping the garbage collector
is the use of System.gc() ... Unfortunately, System.gc() triggers a full
collection, which includes tracing all live objects in the heap and sweeping
and compacting the old generation. This can be a lot of work."

<http://www.javaworld.com/javaworld/jw-01-2002/jw-0111-hotspotgc.html>
"The HotSpot JVM uses a two-machine-word object header, rather than the
three-word header found in most other JVMs. This saves as much as 10 percent
of the heap size for typical applications while accelerating the code to scan
all objects.

"The HotSpot JVM also eliminates the concept of handles. This reduces memory
usage and speeds processing. In the HotSpot JVM, object references are
implemented as direct pointers, providing C-speed access to instance variables."

> Inasmuch as Java already does what it can to reduce the number of
> objects it has to inspect during a GC pass, it thus also is already
> doing what it can to reduce the active working set, reducing page swapping.

In what writers call "typical" usage patterns, it is claimed that 90-98% of
objects are dead before they get promoted to the tenured generation. That
means the young-generation collector only needs to visit 2-10% of the objects
in the nursery to do a collection.

> Whether that qualifies in your mind as "virtual-memory-swap aware", I'm
> not sure. But I think it's safe to say that the Sun developers who are
> responsible for the JVM and its memory management implementation fully
> expect Java to be running on systems with virtual memory management and
> a swap file, and do take that into account to the extent that they can.

To respond to Roedy's question, everything I've read about the 'System.gc()'
call suggests that it's unwise to use. OTOH, I've heard anecdotes in the
field that suggest that it is useful, though none of those anecdotes seem to
come with descriptions of alternatives rejected, such as tuning the JVM's GC
parameters [1]. Some of those anecdotes related to situations where memory
was inappropriately retained ("packratted") and 'gc()' was a band-aid approach
that missed the real problem.

Simple logic suggests to me that hard-coded 'gc()' calls cannot "know" when
memory is tight, but the JVM always will. That means that 'gc()' will never
do better than regular GC at creating free memory when it's needed. As to
making it faster, if memory is not tight then triggering a 'gc()' is
unnecessary and therefore not "faster" in any useful sense. If memory is
tight, the JVM will trigger a GC anyway, so asking for it does not help. If
'gc()' doesn't help when memory is not tight, nor when memory is tight, then
there's never a need to call it.

If you think that 'gc()' might help, run the program in question twice under
load for a long time with the 'gc()' calls in place, once without the option
"-XX:-DisableExplicitGC" and once with. Measure the difference.

[1]
<http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html>
<http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html>


--
Lew

Peter Duniho

unread,
Nov 27, 2009, 1:27:56 AM11/27/09
to
Lew wrote:
> Peter Duniho wrote:
>> To the extent that a smaller working set reduces paging, anything Java
>> can do to reduce the amount of memory it actually accesses would be
>> productive. But that is already a basic goal, even ignoring
>> page-swapping issues. GC is more costly the more objects that need to
>> be inspected, even if all those objects are already swapped-in.
>>
>> And in fact, the Java GC implementation has features intended to
>> address that goal of reducing memory accesses (e.g. object generations).
>
> Young-generation collections don't touch dead objects.

So? It's not the dead objects that are the problem.

> [...]


>> Inasmuch as Java already does what it can to reduce the number of
>> objects it has to inspect during a GC pass, it thus also is already
>> doing what it can to reduce the active working set, reducing page
>> swapping.
>
> In what writers call "typical" usage patterns, it is claimed that 90-98%
> of objects are dead before they get promoted to the tenured generation.
> That means the young-generation collector only needs to visit 2-10% of
> the objects in the nursery to do a collection.

Note also that even if it's true that 90-98% of all objects are
unreachable before the next GC operation since they were created (i.e.
"are dead before they get promoted"), that doesn't mean an application
may not have a large number of objects in the tenured generation(s).

So, as importantly, a collection that only collects the nursery need not
touch all the other longer-lived objects that are tenured.

> To respond to Roedy's question, everything I've read about the
> 'System.gc()' call suggests that it's unwise to use. OTOH, I've heard

> anecdotes in the field that suggest that it is useful, [...]

I have yet to see a solid description of a scenario in which forcing GC
is beneficial. That said, assuming such a scenario exists, I'd say that
generally, a developer qualified to properly implement forceful GC is
qualified enough to _know_ for sure why they are doing it, and whether
it will help.

Sort of "if you have to ask, you shouldn't be doing it".

I realize that doesn't address the academic nature of the original
question, but I feel reasonably confident that my failure to add a
forceful GC to my code doesn't reflect a failing in that code. Not
having enough experience to make that judgment, I'd probably just screw
things up worse adding it. :)

Pete

Lew

unread,
Nov 27, 2009, 9:31:07 AM11/27/09
to
Lew wrote:
>> Young-generation collections don't touch dead objects.

Peter Duniho wrote:
> So? It's not the dead objects that are the problem.

So? As you yourself said,


> So, as importantly, a collection that only collects the nursery need not
> touch all the other longer-lived objects that are tenured.

So, calling GC forces a full collection, so the tenured generation gets hit,
so you lose the benefit of the young-generation collection, so one should not
so force a collection, for that and other reasons so stated by you.

It's relevant because people thinking of calling 'gc()' may believe that the
total number of objects allocated is relevant, and should be aware that it's
generally only the number of live objects that affect GC time.

As for another point you made,
> an application may ... have a large number of objects
> in the tenured generation(s).

This is an important point. Many of the things people naively do to "help"
GC, such as reuse of a single object throughout a loop instead of reallocation
in each iteration, force promotion of objects to the tenured generation and
actually hurt memory management. They also tend to promote the scope of
references outside the block where they're used, a bad practice. It is
usually better to limit the lifetime of objects so they get dropped during
minor collections, keeping the size of the tenured generation as small as
practicable. This tends to help limit reference scope also.

Another benefit to keeping lifetimes short is that it helps prevent references
from tenured-generation objects into the young generation, another situation
that unnecessarily tenures objects.

--
Lew

Arne Vajhøj

unread,
Nov 27, 2009, 8:46:36 PM11/27/09
to
Roedy Green wrote:
> The general advice we tend to give is don't use System.gc. Just let
> the system do its thing. Further, calling it does not FORCE garbage
> collection, just suggests it may be a good time for it.
>
> Are there any exceptions to this general rule?
>
> e.g. when you know the system will likely be idle for a while.
>
> when you know the number of live objects is at a minimum just now.

It will never make a not working program work.

Unless you happen to be a GC expert, then it could just as well
make performance worse as improve performance.

The only good reason to put it in the code is if you are paid
by line - in which case adding an extra line gets you extra money.

Arne

Kevin McMurtrie

unread,
Nov 28, 2009, 10:37:18 PM11/28/09
to
In article <oqbsg5h2ukkv6e5vc...@4ax.com>,
Roedy Green <see_w...@mindprod.com.invalid> wrote:

> The general advice we tend to give is don't use System.gc. Just let
> the system do its thing. Further, calling it does not FORCE garbage
> collection, just suggests it may be a good time for it.
>
> Are there any exceptions to this general rule?
>
> e.g. when you know the system will likely be idle for a while.
>
> when you know the number of live objects is at a minimum just now.

There are some bugs in Java 1.5 that can be helped with a periodic
forced GC:

- File descriptor leaks in NIO
- CMS auto-tuning into oblivion
- CMS lockups due to heap complexity

I haven't seen them yet in 1.6. Of course, calling System.gc() is a
workaround with severe impacts on performance. By default it invokes
the slowest type of GC available. It's better to solve the original
problem.
--
I won't see Goolge Groups replies because I must filter them as spam

0 new messages