Java Forum / General / June 2007
Forcing System.gc()
R. Vince - 07 Jun 2007 14:42 GMT 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
Eric Sosman - 07 Jun 2007 17:00 GMT 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. [quoted text clipped - 3 lines] > 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.
 Signature Eric.Sosman@sun.com
Philipp Leitner - 07 Jun 2007 23:49 GMT > 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
Twisted - 08 Jun 2007 02:13 GMT > 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.
Matt Humphrey - 08 Jun 2007 02:19 GMT |> 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 [quoted text clipped - 14 lines] | 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 matth@ivizNOSPAM.com http://www.iviz.com/
Philipp Leitner - 08 Jun 2007 11:10 GMT > 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
Patricia Shanahan - 08 Jun 2007 14:15 GMT >> 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.
Patricia
Lew - 08 Jun 2007 15:11 GMT > 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.
 Signature Lew
Matt Humphrey - 08 Jun 2007 17:46 GMT | >> 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 [quoted text clipped - 9 lines] | 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 matth@ivizNOSPAM.com http://www.iviz.com/
Eric Sosman - 08 Jun 2007 18:13 GMT 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 [quoted text clipped - 22 lines] > 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 ...
 Signature Eric.Sosman@sun.com
Mark Space - 08 Jun 2007 20:33 GMT > 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...
Twisted - 08 Jun 2007 20:53 GMT > > 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 [quoted text clipped - 5 lines] > 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.
Mark Space - 09 Jun 2007 01:45 GMT > 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.
Stefan Ram - 09 Jun 2007 02:39 GMT >I suppose then that Java references can't be pointers at all, >because moving objects in the heap would invalidate those pointers. »(...) reference values (...) are pointers«
JLS3, 4.3.1.
http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.3.1
Twisted - 09 Jun 2007 04:05 GMT > >I suppose then that Java references can't be pointers at all, > >because moving objects in the heap would invalidate those pointers. [quoted text clipped - 4 lines] > > http://java.sun.com/docs/books/jls/third_edition/html/typesValues.htm... Either it uses double indirection, or (more likely) it updates all the references when it compacts an object. It can do this -- the gc will have found those references when mapping the object graph and deciding whether the object was garbage or not.
Arne Vajhøj - 09 Jun 2007 19:32 GMT >> Shouldn't be. The thorough GC tried before throwing OOME should >> compact all the surviving objects into one or two contiguous blocks [quoted text clipped - 8 lines] > 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
Twisted - 10 Jun 2007 05:16 GMT On Jun 9, 2:32 pm, Arne Vajh?j <a...@vajhoej.dk> wrote:
> I think that it is left to the JVM implementation to decide > how is will do it. [quoted text clipped - 3 lines] > > 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).
David Gourley - 11 Jun 2007 22:20 GMT > 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
Twisted - 12 Jun 2007 04:07 GMT On Jun 11, 5:20 pm, David Gourley <d...@NOSPAM.gourley.plus.com> wrote:
> The annoying thing is I've seen situations where OOME is caused by > unfinalized objects with native memory associated which exhaust the [quoted text clipped - 3 lines] > 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.)
Arne Vajhøj - 08 Jun 2007 03:28 GMT > I have an app that, at one point, really bogs down as so many objects are > created and released in a lengthy process. [quoted text clipped - 5 lines] > > 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
Roedy Green - 15 Jun 2007 10:57 GMT >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? Try it. It might ignore you anyway. At worst it will go slower, and you take them out. -- Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Thomas Schodt - 15 Jun 2007 11:32 GMT > I have an app that, at one point, really bogs down as so many objects are > created and released in a lengthy process. [quoted text clipped - 3 lines] > 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? One scenario where you might get a better responsiveness is calling gc() when a Java GUI application is minimized (or loses focus).
If you don't, imagine the OS swapping the memory out and when you switch back to the application one of the first things that happens is the JVM decides it needs to do a gc run - a lot of that heap must first be swapped back in.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|