Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

  1. Is line 5 needed? Is there any other substitute?
  2. 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) Ans 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

like image 793
Jatin Avatar asked Dec 13 '25 05:12

Jatin


2 Answers

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, and

  • forcing 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.

like image 85
Stephen C Avatar answered Dec 14 '25 20:12

Stephen C


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.

like image 29
Paolo Avatar answered Dec 14 '25 19:12

Paolo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!