Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java GC:old generation becomes larger and larger and cannot be reclaimed

I am writing my servlet program and use jconsole and jmap to monitor its memory status.I find that when my program is running , Memory Pool "PS Old Gen" is becoming larger and larger and finally my servlet cannot respond to any request.

This is the shotcut of my JConsole output:

enter image description here

When I click the "Perform GC" Button, Nothing happened.

So , to see the details ,I use jmap to dump the details:

enter image description here

And this is my JConsole VM Summary output: enter image description here Any one can help me to get out what may be the problem?Your know , the GC "PS MarkSweep" and "PS SCavenge" is the default GC for my Server JVM.

Thank you.


I find a very weird phenomenon:During 15 hours from 18:00 of yesterday to 09::00 of today ,it seems that GC on "PS Old Gen" never occurred , which make the used memory of old generation is becoming larger and larger.i have just manually click the "Perform GC" button ,it seems that this GC is quite effective and reclaim a lot of memory. But why the Old generation GC didn't happen automatically for such a long time? We can see that before 18:00 of yesterday , the old generation GC is working properly. enter image description here

like image 919
wuchang Avatar asked Sep 17 '14 08:09

wuchang


1 Answers

Assuming that you did not add the option -histo:live when you were taking the jmap, which will result in taking the report with garbage + live objects, and referring to the memory drop happened when you manually click the "Perform GC" button, I doubt that the application don't have a memory leak but a bad object promotion rate from the Young Gen to Old Gen. Eventually the Old Gen will be filled up and will run full GC resulting the application to go unresponsive.

If my assumption is correct, I think your strategy should be to minimize promoting the objects to old gen. Rather than worrying about what to do to clear out the Old Gen which is more expensive. Referring the below comments you have mentioned, I think you application has a small Memory Footprint (< 0.5G ) relative to the max allocated memory 7G .

"All my data-intensive variables are defined in method. When method returned , these variables should be reclaimed, right?"

So there are few things you can do.

  • Tune the application to minimize the response times of your transactions so that the objects will be garbage collected before been promoted to the Old Gen

  • Increase the Young Gen size. Since you have around 7 GB to play with, why don't you allocate around 2 - 3 GB to Young Gen for a start ( i.e -XX:NewSize=2g ). A larger New Size will reduce the frequency of PCSacavenge ( Young Collections) and will reduce the rate of aging the live objects.

  • Then start adjusting the -XX:MaxTenuringThreshold=n . You can us the gc.log with -XX:+PrintTenuringDistribution. Size the survivor ratios -XX:SurvivorRatio=n. Note that by default -XX:+UseAdaptiveSizePolicy is on and this will alter the initial size of Survivor Ratios dynamically. Or else you can skip sizing the Survivor Ratios leaving the AdaptiveSizePolicy to do the job. But I'm not a big fan of AdaptiveSizePolicy.

  • Along with AdaptiveSizePolicy you can use -XX:MaxGCPauseMillis=n in order to give an indication to the Garbage Collector regarding the pauses you are expecting in your application when clearing the Old Gen. In this way the Collector will try to achieve the MaxGCPauseMillis by not waiting until there is too much work to do.

  • Or else you can switch to CMS collector which is built to handle response time issues like these.

Well I think if first two steps resolves your problem then you can leave the rest aside. You must not spoil a well running app by adding some additional stuff. Important thing is you have to tune the GC step by step.

like image 111
Tharanga Hewavithana Avatar answered Sep 28 '22 04:09

Tharanga Hewavithana