Forcing System.gc()

R

R. Vince

I have an app that, at one point, really bogs down as so many objects are
created and released in a lengthy process.

I am wondering if I may not be able to improve performance by System.gc() in
some "right" places in my code (wherever those might be!). It seems to me
though, that the gc facilities in Java are so good, that this is something
best left up to the JVM, and NOT mess with putting System.gc() in anyplace?

I am on WinXP / Vista and JRE 1.6.x. TIA, R. Vince
 
E

Eric Sosman

R. Vince wrote On 06/07/07 09:42,:
I have an app that, at one point, really bogs down as so many objects are
created and released in a lengthy process.

I am wondering if I may not be able to improve performance by System.gc() in
some "right" places in my code (wherever those might be!). It seems to me
though, that the gc facilities in Java are so good, that this is something
best left up to the JVM, and NOT mess with putting System.gc() in anyplace?

The usual wisdom is that the JVM has a more accurate
idea of the state of memory than you do. Its decisions
about when to collect garbage, since they are made in
light of the actual run-time memory pressure, are likely
to be better than static decisions you make at coding
time without benefit of the JVM's knowledge.

In very rare cases you might do better than the JVM,
because the knowledge advantage is not entirely one-sided.
The JVM has better information than you do on the current
state and recent history of memory, but has no knowledge
of the program's future behavior. You may be able to
exploit your foreknowledge to choose a better moment for
GC than the JVM would if left to its own devices.

... but such cases are likely to be extremely rare.
About the only scenario I can come up with is a program
that runs in "waves:" it creates a huge population of
objects, then throws nearly all of them away, and then
repeats. You might get some advantage by running GC in
the "troughs," just after the great object die-off and
before the ensuing population boom. But that's "might"
as in "it's conceivable, I suppose," and not a promise of
any benefit -- it's not even a promise of no harm!

Suggestion: Gather some statistics on the actual GC
behavior of your program. If you find that GC is a problem,
your next step should be to find out why it runs so often
and so hard: Are you creating and discarding objects sub-
optimally, as in

String s = "";
for (String s2 : hugeCollectionOfStrings)
s += s2;

Reducing "object churn" will probably do more to help with
GC than quite a lot of GC-centered fiddling. (Memory
profilers may also be of help here.)

If GC is still a problem even after you've done all you
can to use your objects intelligently, then and only then
should you resort to fiddling with the GC itself. And if
you do, be sure to measure what happens and compare with
the original, pre-fiddling measurements: "tuning" GC may
actually have made things worse, and it may be necessary to
"de-tune" it just to recover the status quo ante.
 
P

Philipp Leitner

I am wondering if I may not be able to improve performance by System.gc() in
some "right" places in my code (wherever those might be!). It seems to me
though, that the gc facilities in Java are so good, that this is something
best left up to the JVM, and NOT mess with putting System.gc() in anyplace?

Probably. But you can never 'force' the JVM to do garbage collection.
System.gc() will only 'suggest' that now may be a good time to do GC
(but under certain circumstances, I think it has to do with system
load, the JVM might simply ignore the call). Anyway, I think the cost
for calling System.gc() is not huge, so perhaps I think it might be
worth a try.

I for myself remember having used System.gc() exactly once so far - in
one project I was running >200 Unit Tests, and every test case was
creating an in-memory representation of a WSDL file and compiled XML
Schemata using XMLBeans. At some point in the test run the JVM just
stopped with OutOfMemory. Putting a System.gc() at the end of every
single test case solved the problem just nice.

/philipp
 
T

Twisted

I for myself remember having used System.gc() exactly once so far - in
one project I was running >200 Unit Tests, and every test case was
creating an in-memory representation of a WSDL file and compiled XML
Schemata using XMLBeans. At some point in the test run the JVM just
stopped with OutOfMemory. Putting a System.gc() at the end of every
single test case solved the problem just nice.

Looks like a bug in the JVM you were using. If it required too much
memory, it should have had OOME no matter what. On the other hand, if
it didn't, it shouldn't have no matter what. All reclaimable garbage
is supposed to be reclaimed before OOME is thrown; the JLS specifies
this, absent unusual and non-default GC-behavior commandline options
to the JVM. So the GC at the end of every single test should just have
changed one large pause where the OOME would *otherwise* have been
thrown into lots of little pauses sprinkled throughout the testing
routine. It should not have prevented an OOME, just a large pause.
 
M

Matt Humphrey

|> I am wondering if I may not be able to improve performance by System.gc()
in
| > some "right" places in my code (wherever those might be!). It seems to
me
| > though, that the gc facilities in Java are so good, that this is
something
| > best left up to the JVM, and NOT mess with putting System.gc() in
anyplace?
|
| Probably. But you can never 'force' the JVM to do garbage collection.
| System.gc() will only 'suggest' that now may be a good time to do GC
| (but under certain circumstances, I think it has to do with system
| load, the JVM might simply ignore the call). Anyway, I think the cost
| for calling System.gc() is not huge, so perhaps I think it might be
| worth a try.
|
| I for myself remember having used System.gc() exactly once so far - in
| one project I was running >200 Unit Tests, and every test case was
| creating an in-memory representation of a WSDL file and compiled XML
| Schemata using XMLBeans. At some point in the test run the JVM just
| stopped with OutOfMemory. Putting a System.gc() at the end of every
| single test case solved the problem just nice.

Can you explain how your request for gc would prevent an OutOfMemory error?
I thought that OutOfMemory occurs only when gc cannot reclaim any more--it
is never necessary to request gc to prevent OutOfMemory.

Cheers,
Matt Humphrey (e-mail address removed) http://www.iviz.com/
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

R. Vince said:
I have an app that, at one point, really bogs down as so many objects are
created and released in a lengthy process.

I am wondering if I may not be able to improve performance by System.gc() in
some "right" places in my code (wherever those might be!). It seems to me
though, that the gc facilities in Java are so good, that this is something
best left up to the JVM, and NOT mess with putting System.gc() in anyplace?

I am on WinXP / Vista and JRE 1.6.x.

It is most likely that the JVM is much better than your code
to determine what is optimal times to GC and that explicit
calls to System.gc will decrease performance.

Have you tried experimenting with the -X and -XX JVM parameters
that controls GC ?

Arne
 
P

Philipp Leitner

Can you explain how your request for gc would prevent an OutOfMemory error?
I thought that OutOfMemory occurs only when gc cannot reclaim any more--it
is never necessary to request gc to prevent OutOfMemory.

No, I can't. I really didn't think much about it so far, but it
definitely worked.

/philipp
 
P

Patricia Shanahan

Philipp said:
No, I can't. I really didn't think much about it so far, but it
definitely worked.

Here's one random explanation...

Suppose one of the objects has a finalizer that creates some new
objects. That would be fine if it were finalized while there is plenty
of free memory, as would be the case with a System.gc call at the end of
every cycle of the program.

Patricia
 
L

Lew

Patricia said:
Suppose one of the objects has a finalizer that creates some new objects.

What a dark and evil notion.

I catch grief for finalizers that release resources, just in case the regular
methods didn't.

Now that you have me imagining, I conceive of finalizers that spawn new
threads with their own service cycles, external connections, ...

I hope I awaken soon.
 
M

Matt Humphrey

| Philipp Leitner wrote:
| >> Can you explain how your request for gc would prevent an OutOfMemory
error?
| >> I thought that OutOfMemory occurs only when gc cannot reclaim any
more--it
| >> is never necessary to request gc to prevent OutOfMemory.
| >
| > No, I can't. I really didn't think much about it so far, but it
| > definitely worked.
|
| Here's one random explanation...
|
| Suppose one of the objects has a finalizer that creates some new
| objects. That would be fine if it were finalized while there is plenty
| of free memory, as would be the case with a System.gc call at the end of
| every cycle of the program.

That's brilliant. If the OOM is inevitable, early gcs could delay it. If
it's not inevitable they could prevent it.

I was thinking that early gcs might affect how objects enter generations,
but supposedly that wouldn't matter because the gc before a OOM would always
be as thorough as possible.

Cheers,
Matt Humphrey (e-mail address removed) http://www.iviz.com/
 
E

Eric Sosman

Matt Humphrey wrote On 06/07/07 21:19,:
|> I am wondering if I may not be able to improve performance by System.gc()
in
| > some "right" places in my code (wherever those might be!). It seems to
me
| > though, that the gc facilities in Java are so good, that this is
something
| > best left up to the JVM, and NOT mess with putting System.gc() in
anyplace?
|
| Probably. But you can never 'force' the JVM to do garbage collection.
| System.gc() will only 'suggest' that now may be a good time to do GC
| (but under certain circumstances, I think it has to do with system
| load, the JVM might simply ignore the call). Anyway, I think the cost
| for calling System.gc() is not huge, so perhaps I think it might be
| worth a try.
|
| I for myself remember having used System.gc() exactly once so far - in
| one project I was running >200 Unit Tests, and every test case was
| creating an in-memory representation of a WSDL file and compiled XML
| Schemata using XMLBeans. At some point in the test run the JVM just
| stopped with OutOfMemory. Putting a System.gc() at the end of every
| single test case solved the problem just nice.

Can you explain how your request for gc would prevent an OutOfMemory error?
I thought that OutOfMemory occurs only when gc cannot reclaim any more--it
is never necessary to request gc to prevent OutOfMemory.

Might a really memory-hungry finalize() cause such
a thing? I imagine that if finalization uses a lot of
memory, running GC early could schedule deceased objects
for finalization while memory is still plentiful, while
postponing GC until memory is scarce might leave too
little for the finalizers' use. (I hasten to add that
I don't say things *would* play out this way, just that
it seems to me that they might -- I'm entirely ready to
be corrected by someone who knows better.)

A memory-hungry finalizer seems an awfully silly
thing to write -- but that doesn't mean nobody writes
them ...
 
M

Mark Space

Matt said:
Can you explain how your request for gc would prevent an OutOfMemory error?
I thought that OutOfMemory occurs only when gc cannot reclaim any more--it
is never necessary to request gc to prevent OutOfMemory.


Would it be possible that long running code without garbage collection
left the heap so fragmented that the largest available memory block
wouldn't hold some object that needed to be allocated? That's all I can
think of. I don't know enough about JVM and memory allocation to know
if this is even a likely scenario...
 
T

Twisted

Would it be possible that long running code without garbage collection
left the heap so fragmented that the largest available memory block
wouldn't hold some object that needed to be allocated? That's all I can
think of. I don't know enough about JVM and memory allocation to know
if this is even a likely scenario...

Shouldn't be. The thorough GC tried before throwing OOME should
compact all the surviving objects into one or two contiguous blocks
(maybe two with generational GC). Heap fragmentation is for C++
programmers to fret about. ;)

As for a finalizer allocating memory, I'd sort of assumed an absence
of such questionable code. If there is one, though, it could explain a
thing or two. And demonstrate why finalizers are evil, and should only
ever be used to make sure file handles and such are (eventually)
released and never to do anything more complicated than close a stream
here or null out a reference there.
 
M

Mark Space

Twisted said:
Shouldn't be. The thorough GC tried before throwing OOME should
compact all the surviving objects into one or two contiguous blocks
(maybe two with generational GC). Heap fragmentation is for C++
programmers to fret about. ;)

Useful to know, thanks. ^_^ I suppose then that Java references can't
be pointers at all, because moving objects in the heap would invalidate
those pointers. And going through the code and updating all references
on the fly seems... ugly, to say the least. Maybe references work
something like handles in the old Mac OS? Pointers to pointers, where
the second pointer is the thing that gets updated when objects on the
heap are re-allocated or moved.
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

Mark said:
Useful to know, thanks. ^_^ I suppose then that Java references can't
be pointers at all, because moving objects in the heap would invalidate
those pointers. And going through the code and updating all references
on the fly seems... ugly, to say the least. Maybe references work
something like handles in the old Mac OS? Pointers to pointers, where
the second pointer is the thing that gets updated when objects on the
heap are re-allocated or moved.

I think that it is left to the JVM implementation to decide
how is will do it.

Note that it already to go through a lot of stuff to find out
what can be GC'ed.

Possibility of reuse !

Arne
 
T

Twisted

I think that it is left to the JVM implementation to decide
how is will do it.

Note that it already to go through a lot of stuff to find out
what can be GC'ed.

Possibility of reuse !

Certainty of reuse. Sun's VM (the defacto reference implementation)
definitely does do this. With generational GC, it determines if an
object is still live, then copies live objects to a growing contiguous
block of them in memory, which becomes the mature generation or some
such terminology. At the time it copies a particular object it has
pointers to that object's inbound references in memory, from when it
determined its reachability, and on copying it diddles them to point
to the object's new location, presumably while suspending the running
code (so-called "stop the world" gc). It may do incremental GCs that
don't copy objects or "stop the world" depending on settings, with
more thorough, "stop the world" compacting collections when necessary
(due to fragmentation, for instance).
 
D

David Gourley

Twisted said:
Shouldn't be. The thorough GC tried before throwing OOME should
compact all the surviving objects into one or two contiguous blocks
(maybe two with generational GC). Heap fragmentation is for C++
programmers to fret about. ;)

But there is one big, big assumption here: that the only cause of OOME
is exhausting the (Java) heap. Actually this is one of my biggest
annoyances about Java, especially 32-bit implementations.

You can get OOME attempting to create a thread if there isn't memory to
create the thread's stack (which is actually a native memory issue).

You can get OOME from some mixed language classes if the *native* memory
can't get created associated with instances of those classes (there are
some of these in the java library that allocate native memory as well as
Java memory - always close these objects and don't leave for finalisation).

The annoying thing is I've seen situations where OOME is caused by
unfinalized objects with native memory associated which exhaust the
process's address space (without* causing a garbage collect (as garbage
collection is triggered by behaviour of the Java heap, not the overall
address space of the process). It would be good to have some kind of
setting to trigger a garbage collect if a process's size hit some kind
of threshold as well...

Dave
 
T

Twisted

The annoying thing is I've seen situations where OOME is caused by
unfinalized objects with native memory associated which exhaust the
process's address space (without* causing a garbage collect (as garbage
collection is triggered by behaviour of the Java heap, not the overall
address space of the process). It would be good to have some kind of
setting to trigger a garbage collect if a process's size hit some kind
of threshold as well...

This is real screwy. The JVM *should* stop the world and do a complete
gc and finalization and repeat gc and finalization until nothing new
shows up as garbage, when it is about to throw OOME *for any reason*,
and then retry the allocation, before then actually throwing OOME.
(This would require, I suppose, JNI code to call a malloc-substitute
that does this stuff behind the scenes and retries before returning
NULL, or in C++ a custom operator-new that does likewise before
throwing bad_alloc. If malloc and new are already substituted with
versions that generate OOME in the JVM automatically on failure in the
JNI environment, then this is (comparatively) trivial. Otherwise it
may well be nontrivial and likely will not be back-compatible with
legacy JNI-using code.)
 

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,756
Messages
2,569,540
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top