我们知道,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
分享到:
相关推荐
其主要缺点是会造成内存碎片化,导致内存空间的利用率降低。 2. 标记整理算法:它解决了标记清除算法中内存碎片化的问题。通过移动存活对象,使得存活对象都移动到内存的一端,然后清理掉端边界以外的内存。老年代...
- **缺点**:容易造成内存碎片化,当碎片积累过多时,可能会导致系统性能下降甚至崩溃。 ##### 2. Copying(复制)算法 **定义与原理**:为了解决Mark-Sweep算法中内存碎片化的问题,引入了复制算法。该算法将可用...
但这种算法容易造成内存碎片。 3. **复制(Copying)**:将内存分为两个相等的部分,每次只使用其中一部分,当这一部分的空间用尽时,就将还存活的对象复制到另一部分中,然后再清除已使用过的空间。 4. **增量收集...
还有一个问题就是碎片化,因为CMS在清除垃圾时不进行压缩,长期运行后可能导致内存区域变得高度碎片化,影响分配大对象的能力。 为了解决这些问题,Oracle在JDK 9中引入了G1(Garbage-First)垃圾收集器,它在保持...
这种方法会产生内存碎片。 - **标记-压缩算法**:在标记-清除的基础上,将存活对象移动到内存的一端并压缩,避免碎片问题,但需要停止整个应用执行。 - **复制算法**:将堆分为两部分,每次只使用一部分,当这部分...
标记阶段找出所有活动对象,清除阶段回收无用对象占用的空间,压缩阶段则将存活对象紧凑排列,消除内存碎片。 5. **内存分区**:现代的垃圾收集器通常会将堆内存划分为新生代(Young Generation)和老年代(Old ...
3. **标记-整理算法**:标记过程与标记-清除算法一致,但是在清除完成后会整理所有活着的对象到内存的一端,这样可以避免内存碎片的问题。 ### 什么是记忆集,什么是卡表?记忆集和卡表有什么关系? 1. **记忆集**...