CMSGC造成內存碎片的解決方法


我們知道,CMSGC在老生代回收時產生的內存碎片會導致老生代的利用率變低;或者可能在老生代總內存大小足夠的情況下,卻不能容納新生代的晉升行為(由於沒有連續的內存空間可用),導致觸發FullGC。針對這個問題,Sun官方給出了以下的四種解決方法:

  • 增大Xmx或者減少Xmn
  • 在應用訪問量最低的時候,在程序中主動調用System.gc(),比如每天凌晨。
  • 在應用啟動並完成所有初始化工作后,主動調用System.gc(),它可以將初始化的數據壓縮到一個單獨的chunk中,以騰出更多的連續內存空間給新生代晉升使用。
  • 降低-XX:CMSInitiatingOccupancyFraction參數以提早執行CMSGC動作,雖然CMSGC不會進行內存碎片的壓縮整理,但它會合並老生代中相鄰的free空間。這樣就可以容納更多的新生代晉升行為。


原文引用:

引用
What should you do if you run into a fragmentation problem?
Try 5.0.
Or you could try a larger total heap and/or smaller young generation. If your application is on the edge, it might give you just enough extra space to fit all your live data. But often it just delays the problem.
Or you can try to make you application do a full, compacting collection at a time which will not disturb your users. If your application can go for a day without hitting a fragmentation problem, try a System.gc() in the middle of the night. That will compact the heap and you can hopefully go another day without hitting the fragmentation problem. Clearly no help for an application that does not have a logical "middle of the night".
Or if by chance most of the data in the tenured generation is read in when your application first starts up and you can do a System.gc() after you complete initialization, that might help by compacting all data into a single chunk leaving the rest of the tenured generation available for promotions. Depending on the allocation pattern of the application, that might be adequate.
Or you might want to start the concurrent collections earlier. The low pause collector tries to start a concurrent collection just in time (with some safety factor) to collect the tenured generation before it is full. If you are doing concurrent collections and freeing enough space, you can try starting a concurrent collection sooner so that it finishes before the fragmentation becomes a problem. The concurrent collections don't do a compaction, but they do coalese adjacent free blocks so larger chunks of free space can result from a concurrent collection. One of the triggers for starting a concurrent collection is the amount of free space in the tenured generation. You can cause a concurrent collection to occur early by setting the option -XX:CMSInitiatingOccupancyFraction= where NNN is the percentage of the tenured generation that is in use above which a concurrent collection is started. This will increase the overall time you spend doing GC but may avoid the fragmentation problem. And this will be more effective with 5.0 because a single contiguous chunk of space is not required for promotions.


我在實際應用中的調優是:

  • 在應用啟動並完成所有初始化工作后,主動調用System.gc()。
  • 在Xmx不變的情況下,保持SuvivorSpace不變(為了不讓每次MinorGC的晉升大小增加),降低Xmn。
  • 降低-XX:CMSInitiatingOccupancyFraction


我認為在程序中調用System.gc()並不是一個很好的選擇,因為:

  • FullGC一定會導致應用暫停,而有些高並發應用是不允許有一次FullGC的,so...
  • 在jdk1.6的某個版本中,調用System.gc()並且應用中有nio操作的話,會導致應用掛起的Bug


另外的一種方法是(沒用過,僅供參考):
http://kenwublog.com/avoid-full-gc-in-hbase-using-arena-allocation


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM