Garbage collection overload, Java
The problem is that some how due to garbage collection timings I am having tradeoff's in my performance. The issue can be generalized as:
public void loop(BlockingQueue<Runnable> queue)
{
int j = queue.size();
for(int i =0; i<j;i++)//line2
{
Runnable runnable = queue.take();
runnable.run();//line4
if(Math.random() > 0.9) System.gc();//line5
}
//line7 //will 'runnable = null;' answer the question, logically it looks right
}
Now normally the queue passed as argument will contain more than 40,000 elements normally. And because I am iterating over the queue in a loop, even though the already 'run' objects are out of scope, they are still not available for garbage Collection because they are in invisible state. Hence if I do not have the line 5, then suddenly there will be a huge load on the garbage collector when the method goes out of the stack. Imagine if concurrently many thread accessing the menthod.
My questions:
- Is line 5 needed? Is there any other substitute?
- If I have to have line 5, I found out the performance was very very bad when compared to not having it.
Ultimately garbage collection has to happen? I am unable to figure out when it should happen.
PS: Javascript is disabled on my computer hence can't comment for answers. I shall edit the post here for the comments:
@amit: I have changed the code, I think you have understood the essence of the problem. The code is just a sample.
@Tobi: Thanks, but how will setting up a bigger heap size, solve the problem. Thats only delaying the time of gc. So you think it will perform the best without manual gc? Further from http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html, it says that only once the method is taken of the stack, only then in this case it would be available for garbage collection. And i tried with finalize() (by having a print, not the right way, but should atleast work once for 100000 objects), there is absolutely no gc.
@Paolo: Thanks. What i am trying to implement is a pipelining model, where every thread has a meassage queue, basically a framework where any thread can post a runnable to the other thread (if it has some work with the thread), and the other thread will execute them after soem time(when it is idle) An开发者_高级运维s when i meant, overload when the method comes out of the stack, what i mean is that garbage colelction will eventually happen, if it happens later, then clearing 40,000 elements will take a lot time
@ Joachim Sauer : System.gc can collect invisible objects, It is just that garbage collector doesn't collect them automatically. But when forced, it does as per: http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html
1) Is line 5 needed? Is there any other substitute?
The call to System.gc()
is unnecessary. In fact, it is positively harmful for throughput to call System.gc()
.
Just delete line 5. There is no need to replace it with anything.
2) If I have to have line 5, I found out the performance was very very bad when compared to not having it.
This is entirely as I would expect. See above.
And because I am iterating over the queue in a loop, even though the already 'run' objects are out of scope, they are still not available for garbage Collection because they are in invisible state
In fact:
there can be at most one object in "invisible" state referenced by an out-of-scope
runnable
variable, andforcing garbage collection won't reclaim it anyway.
System.gc can collect invisible objects.
This statement is false. In fact the problem of invisible objects is that the GC can't collect them. Indeed, the article you linked to says this very clearly:
"Because invisible objects can't be collected, this is a possible cause of memory leaks. If you run into this situation, you might have to explicitly null your references to enable garbage collection."
(Emphasis added.)
Frankly, I think you are trying to solve a problem that does not exist. Or if it does exist, it is nothing to do with invisible objects.
And if there really is a problem with invisible objects, then the solution is to simply assign null
to the variable at the end of the loop.
Fundamentally you are not supposed to figure out when to collect garbage, that is up to the JVM. Line 5 is unnecesary and as you've spotted will be detrimental to your application's performance.
Trying to force the GC repeatedly means you've got something wrong with the design of your program.
suddenly there will be a huge load on the garbage collector when the method goes out of the stack.
Not necessarily, the GC doesn't run every time objects go out of scope or a stack frame is popped. The JVM determines when to do a GC run and this may be immediately, it may be sometime in the future.
What are you trying to achieve in this method? It looks like you have a collection of tasks you want to execute in parallel? If this is the case you should be looking at the ExecutorService to put tasks on a thread pool for you.
Let the garbage collector do its work, and if necessary (and only then), tune the garbage collector using VM arguments, but do not put a call to System.gc()
in an inner loop like this.
It is pretty much guaranteed that such a call will kill performance, because it forces a full garbage collection cycle, while normally the garbage collector 1) only collects when the heap is nearly full (so you can reduce/increase the number of collections by giving the VM a larger/smaller heap), and 2) only collects the youngest objects most of the time (i.e., generational garbage collection).
As for your particular case, invisible state means that the object referenced by the variable runnable may still be strongly referenced at line 7, even though the local variable runnable
is out of scope at that point. However, the vm only reserves one slot for the variable runnable, which is reused in each iteration of your loop. As soon as you take the next element from the queue and store it in runnable
, it will overwrite the reference to the previous element, therefore making this previous element eligible for garbage collection. In other words, only one element will likely ever be in this invisible state (per call to loop
).
Just some thought that may be of help or not.
- Have you tried Java 7 as they claim far greater gc performance.
- You can try playing with vm arguments
精彩评论