I'm running a scheduling algorithm with a garbage collection snippet that looks like this:
//garbage collection
if (state.children.isEmpty()) {//if this is a leaf node (no children)
state.parent.children.remove(state);
System.gc();
}
At first, the algorithm runs smoothly with no pauses; but after a while as the tree starts getting bigger, there's some sort of pause at each gc.
So I thought, maybe if a called gc less frequent? And modified my code to this:
//garbage collection
if (state.children.isEmpty()) {//if this is a leaf node (no children)
state.parent.children.remove(state);
if(index % 10000)
System.gc();
}
But this doesn't seem to actually do any cleanup, my program would throw an outOfMemory exception anyways.
How should I implement my garbage collector correctly so as not to be called too many times?
You shouldn't need to call the garbage collector explicitly at all. It's very occasionally appropriate, but I would normally be pretty suspicious if you find you need it.
Have you tried running with detailed GC logging turned on? It can be awkward to understand at first, but it should show you what's going on. I wouldn't be surprised to find that actually you've got a leak somewhere, and it's just that by GC-ing on every iteration, you've slowed your program down enough so that you just haven't reached the point at which it bites.
How much memory have you allocated for the VM? Tweaking the memory settings (and indeed the GC settings) can have a big impact on some workloads.
The pause is probably garbage collection happening. As Frederik mentions, are you sure you have to invoke the GC manually? Generally you shouldn't need to. If you're concerned about your memory usage, feel free to prune your tree more often, but let the GC handle when to run, and don't invoke it manually.
You mentioned that your second snippet results in OutOfMemoryExceptions though, so maybe you have some other problems going on, you might want to show some more code.
Related
I am testing the usage of Heap size in a java application running in JDK 1.6. I use the tool VisualVM to monitor the heap usage. I found the Maximum heap size usage of around 500 MB for a few mins. I used the option "Perform GC" which calls System.gc(). The first time i used it, the Maximum heap is reduced to 410MB, then once again I used it to get 130MB and the next time to 85MB. I made all the four calls next to next without any interval. Why does the call System.gc() does not collect all the Heap to 85MB at first time. Is there any other reason behind this. Or I should try with any other methods?
The System.gc() will return when all objects have been scanned once.
An object should be finalized() AFTER it has been collected. Most objects don't implement this method but for the ones which do, they are added to a queue to be cleaned up later. This means those objects cannot be cleaned up yet (not the queue nodes which hold them) i.e. the act of triggering a GC can increase memory consumption temporarily.
Additionally there are SoftReferences to objects which may or may not be cleaned up by a GC. The assumption is these should only be cleaned up if not much else was cleaned up.
In short, not all objects can be cleaned up in one cycle.
System.gc() requests the JVM to start garbage collection. If you are expecting that GC is invoked as soon as System.gc() then it is a wrong notion. Calling it multiple times will not help. It is not possible to map System.gc() with the actual garbage collection. Also no matter how many times you call System.gc(), JVM will do the GC only when it is ready to do so. What may be happening is that heap size is getting reduced even with the first System.gc() but not exactly as soon as you call it. Garbage collection related to your first System.gc() may be finishing in background and in parallel your code is reaching third System.gc() statement.
If you are pretty sure that only adding multiple System.gc() helps you reducing the heap size. Then you need to check what all objects are getting created in JVM in between first and last System.gc(). There may be other threads creating the objects.
One possible reason might be the use of java.lang.ref.Reference types. If the GC is going to break a "Reference" this will happen after the GC proper has completed. Any objects that become unreachable as a result are left for the next GC cycle to deal with.
Finalization works the same way. If an object requires finalization, it and all of the objects reachable from it (only) are likely to only be collectable in the next GC cycle.
Then there is the issue that the GC's algorithm for shrinking the heap is non-aggressive. According to the Java HotSpot VM Options page, the GC only shrinks the heap if more than 70% is free after garbage collection. However, it is not entirely clear if this refers to a full GC or not. So you could get the GC doing a partial GC and shrinking, and then a full GC and shrinking some more.
(Some people infer from the wording of the System.gc() javadocs that it will perform a full GC. However, I suspect that this is actually version / GC dependent.)
But to be honest this should all be moot. Trying to coerce an application into giving back as much memory is possible is pointless. The chances are that you are forcing it to throw away cached data. When the application gets active again it will start reloading its caches.
This question already has answers here:
How to force garbage collection in Java?
(25 answers)
Closed 8 years ago.
I have a complex java application running on a large dataset. The application performs reasonably fast but as time goes it seems to eat lots of memory and slow down. Is there a way to run the JVM garbage collector without re-starting the application?
No, You cant force garbage collection.
Even using
System.gc();
You can just make a request for garbage collection but it depends on JVM to do it or not.
Also Garbage collector are smart enough to collect unused memory when required so instead of forcing garbage collection you should check if you are handling objects in a wrong way.
If you are handling objects in a wrong way (like keeping reference to unnecessary objects) there is hardly anything JVM can do to free the memory.
From Doc
Calling the gc method suggests that the Java Virtual Machine expend
effort toward recycling unused objects in order to make the memory
they currently occupy available for quick reuse. When control returns
from the method call, the Java Virtual Machine has made a best effort
to reclaim space from all discarded objects.
Open Bug regarding System.gc() documentation
The documentation for System.gc() is extremely misleading and fails to
make reference to the recommended practise of never calling
System.gc().
The choice of language leaves it unclear what the behaviour would be
when System.gc() is called and what external factors will influence
the behaviour.
Few useful link to visit when you think you should force JVM to free up some memory
1. How does garbage collection work
2. When does System.gc() do anything
3. Why is it bad practice to call System.gc()?
All says
1. You dont have control over GC in Java even System.gc() dont guarantee it.
2. Also its bad practise as forcing it may have adverse effect on performance.
3. Revisit your design and let JVM do his work :)
you should not relay on System.gc() - if you feel like you need to force GC to run it usually means that there is something wrong with your code/design. GC will run and clear your unused objects if they are ready to be created - please verify your design and think more about memory management, look as well for loops in object references.
The
System.gc()
call in java, suggest to the vm to run garbage collection. Though it doesn't guarantee that it will actually do it. Nevertheless the best solution you have. As mentioned in other responses jvisualvm utility (present in JDK since JDK 6 update 7), provides a garbage functionality as well.
EDIT:
your question open my appetite for the topic and I came across this resource:
oracle gc resource
The application performs reasonably fast but as time goes it seems to eat lots of memory and slow down.
These are a classic symptoms of a Java memory. It is likely that somewhere in your application there is a data structure that just keeps growing. As the heap gets close to full, the JVM spends an increasing proportion of its time running the GC in a (futile) attempt to claw back some space.
Forcing the GC won't fix this, because the GC can't collect the data structure. In fact forcing the GC to run just makes the application slower.
The cure for the problem is to find what is causing the memory leak, and fix it.
Performance gain/drop depends how often you need garbage collection and how much memory your jvm has and how much your program needs.
There is no certainity(its just a hint to the interpreter) of garbage collection when you call System.gc() but at least has a probability. With enough number of calls, you can achieve some statistically derived performance multiplier for only your system setup.
Below graph shows an example program's executions' consumptions and jvm was given only 1GB(no gc),1GB(gc),3GB(gc),3GB(no gc) heaps respectively to each trials.
At first, when jvm was given only 1GB memory while program needed 3.75GB, it took more than 50 seconds for the producer thread pool to complete their job because having less garbage management lead to poor object creation rate.
Second example is about %40 faster because System.gc() is called between each production of 150MB object data.
At third example, jvm is given 3GB memory space while keeping System.gc() on. More memory has given more performance as expected.
But when I turned System.gc() off at the same 3GB environment, it was faster!
Even if we cannot force it, we can have some percentage gain or drain of performance trying System.g() if we try long enough. At least on my windows-7 64 bit operating system with latest jvm .
Garbage collector runs automatically. You can't force the garbage collector.
I do not suggest that you do that but to force the garbage collector to run from within your java code you can just use all the available memory, this works because the garbage collector will run before the JVM throws OutOfMemoryError...
try {
List<Object> tempList = new ArrayList<Object>();
while (true) {
tempList.add(new byte[Integer.MAX_VALUE]);
}
} catch (OutOfMemoryError OME) {
// OK, Garbage Collector will have run now...
}
My answer is going to be different than the others but it will lead to the same point.
Explain:
YES it is possible to force the garbage collector with two methods used at the same time and in the same order this are:
System.gc ();
System.runFinalization ();
this two methods call will force the garbage collector to execute the finalise() method of any unreachable object and free the memory. however the performance of the software will down considerable this is because garbage runs in his own thread and to that one is not way to controlled and depending of the algorithm used by the garbage collector could lead to a unnecessary over processing, It is better if you check your code because it must be broken to you need use the garbage collector to work in a good manner.
NOTE: just to keep on mind this will works only if in the finalize method is not a reassignment of the object, if this happens the object will keep alive an it will have a resurrection which is technically possible.
I have an array int dom[][] = new int[28][3];, which I move to a different array. How can I free up that array's space? I'm getting high cpu warnings while running it on the android emulator.
In Java, you don't have to free array manually, Garbage collector will clear memory for you. You can just set you object to null: dom = null.
CPU warnings doesn't have anything with this, android emulator has some CPU intensive operations at startup, so your processor will be at 100% some time until emulator starts.
set dom to null. so that it will get freed up when the next Garbage collector runs.
You don't have to do anything: if the array is not reachable any more because you don't have a reference to it, it will be garbage collected (setting the reference to null won't make a difference).
Typically, if this is a local variable and you don't return it from the method where it is declared, it will become eligible for GC as soon as the method exits (i.e. as soon as the array is out of scope).
And if you are "getting high cpu warnings", then the problem is with CPU, not memory.
I'm getting high cpu warnings while running the android emulator?
It could be anything. However, I'm guessing that you've added some explicit System.gc() calls in an attempt to free up space a bit earlier.
Don't do that!
The virtual machine generally knows when there is lots of potential garbage to collect ... and that is the best time to run the GC. And you can be assured that the GC will be run immediately the JVM decides to bail out with an OOME.
If you call System.gc() yourself, the chances are that you will just cause the VM to waste CPU cycles to little useful effect.
In most situations, the best strategy is to let the VM schedule the GC as required. Null'ing references can help, but it is usually unnecessary. (And frankly a 28x3 array of integers takes very little space, and is probably not worth nulling.)
What conditions would prevent the JVM from running a FULL Garbage Collection when the CPU is at 5% to 8% load?
I am seeing a constant shallow GC cycle, but not able to tune the JVM to want to run FULL GC.
Where can I go to find the conditions that the JVM says "I am too busy to run".
When I was studying for my SCJP certification a lot of emphasis was made on
"You can not do anything to force the
GC to run at any given time, you can
just give hints to it"
The whole idea of having an automatic GC is precisely not having to worry about how or when it runs to clean up free memory for you. So, there is no way to actually change when or how GC does actually run... you would have to re-implement one JVM to do what you want.
There are just so many factors involved in this, there may be other, more elegant solutions for this.
It depends entirely on the garbage collector algorithm that you're using in your particular JDK. About all you can guarantee about garbage collection is that if the JVM throws an OutOfMemoryError, the garbage collector made its best effort to collect every unreachable/weakly reachable object. Even System.gc() doesn't guarantee anything, a no-op is a completely legal implementation.
Hence in that light I don't know if your question has any weight. If you truly believe that you need to tweak the garbage collector, it would help if you posted the problems you're seeing, and the profiling data that leads to believe that poor GC performance is the problem.
Outside of this, the garbage collector should be treated like a black box. The logic behind its implementation is surprisingly complex, and there's a very good chance it knows better than you what it ought to be doing at any given time. 99 times out of 100, trying to force the garbage collector to behave in a particular way will lower performance, not increase it.
It's not that it's to busy to run, but it does simply not need extra memory.
I have this class and I'm testing insertions with different data distributions. I'm doing this in my code:
...
AVLTree tree = new AVLTree();
//insert the data from the first distribution
//get results
...
tree = new AVLTree();
//inser the data from the next distribution
//get results
...
I'm doing this for 3 distributions. Each one should be tested an average of 14 times, and the 2 lowest/highest values removed from to compute the average. This should be done 2000 times, each time for 1000 elements. In other words, it goes 1000, 2000, 3000, ..., 2000000.
The problem is, I can only get as far as 100000. When I tried 200000, I ran out of heap space. I increased the available heap space with -Xmx in the command line to 1024m and it didn't even complete the tests with 200000. I tried 2048m and again, it wouldn't work.
What I'm thinking is that the garbage collector isn't getting rid of the old trees once I do tree = new AVL Tree(). But why? I thought that the elements from the old trees would no longer be accessible and their memory would be cleaned up.
The garbage collector should have no trouble cleaning up your old tree objects, so I can only assume there's some other allocation that you're doing that's not being cleaned up.
Java has a good tool to watch the GC in progress (or not in your case), JVisualVM, which comes with the JDK.
Just run that and it will show you which objects are taking up the heap, and you can both trigger and see the progress of GC's. Then you can target those for pools so they can be re-used by you, saving the GC the work.
Also look into this option, which will probably stop the error you're getting that stops the program, and you program will finish, but it may take a long time because your app will fill up the heap then run very slowly.
-XX:-UseGCOverheadLimit
Which JVM you are using and what JVM parameters you have used to configure GC?
Your explaination shows there is a memory leak in your code. If you have any tool like jprofiler then use it to find out where is the memory leak.
There's no reason those trees shouldn't be collected, although I'd expect that before you ran out of memory you should see long pauses as the system ran a full GC. As it's been noted here that that's not what you're seeing, you could try running with flags like -XX:-PrintGC, -XX:-PrintGCDetails,-XX:-PrintGCTimeStamps to give you some more information on exactly what's going on, along with perhaps some sort of running count of roughly where you are. You could also explicitly tell the garbage collector to use a different garbage-collection algorithm.
However, it still seems unlikely to me. What other code is running? is it possible there's something in the AVLTree class itself that's keeping its instances from being GC'd? What about manually logging the finalize() on that class to insure that (some of them, at least) are collectible (e.g. make a few and manually call System.gc())?
GC params here, a nice ref on garbage collection from sun here that's well worth reading.
The Java garbage collector isn't guaranteed to garbage collect after each object's refcount becomes zero. So if you're writing code that is only creating and deleting a lot of objects, it's possible to expend all of the heap space before the gc has a chance to run. Alternatively, Pax's suggestion that there is a memory leak in your code is also a strong possibility.
If you are only doing benchmarking, then you may want to use the java gc function (in the System class I think) between tests, or even re-run you program for each distribution.
We noticed this in a server product. When making a lot of tiny objects that quickly get thrown away, the garbage collector can't keep up. The problem is more pronounced when the tiny objects have pointers to larger objects (e.g. an object that points to a large char[]). The GC doesn't seem to realize that if it frees up the tiny object, it can then free the larger object. Even when calling System.gc() directly, this was still a huge problem (both in 1.5 and 1.6 VMs)!
What we ended up doing and what I recommend to you is to maintain a pool of objects. When your object is no longer needed, throw it into the pool. When you need a new object, grab one from the pool or allocate a new one if the pool is empty. This will also save a small amount of time over pure allocation because Java doesn't have to clear (bzero) the object.
If you're worried about the pool getting too large (and thus wasting memory), you can either remove an arbitrary number of objects from the pool on a regular basis, or use weak references (for example, using java.util.WeakHashMap). One of the advantages of using a pool is that you can track the allocation frequency and totals, and you can adjust things accordingly.
We're using pools of char[] and byte[], and we maintain separate "bins" of sizes in the pool (for example, we always allocate arrays of size that are powers of two). Our product does a lot of string building, and using pools showed significant performance improvements.
Note: In general, the GC does a fine job. We just noticed that with small objects that point to larger structures, the GC doesn't seem to clean up the objects fast enough especially when the VM is under CPU load. Also, System.gc() is just a hint to help schedule the finalizer thread to do more work. Calling it too frequently causes a significant performance hit.
Given that you're just doing this for testing purposes, it might just be good housekeeping to invoke the garbage collector directly using System.gc() (thus forcing it to make a pass). It won't help you if there is a memory leak, but if there isn't, it might buy you back enough memory to get through your test.