网上看到有很多人在讨论 ExplicitGCInvokesConcurrent参数的用途。google了一下,半天都没找到 ExplicitGCInvokesConcurrent究竟为何物,到是发现了 ExplicitGCInvokesConcurrent出现的场景:
1. 很多NIO框架,比如netty会有很多内存映射的代码(memory map),而mmap的内存分配至不会在用Eden区或者old区的,是属于堆外分配,因此,这些框架中会手动调用system.gc来回收mmap分配的空间。(system.gc触发的是full gc,只有full gc时才会回收mmap分配的内存)。
2. 因为NIO框架频繁的调用full gc 会严重影响性能,因此,有人加上了这个参数:-XX:+DisableExplicitGC ,用来禁止system.gc对gc的触发。加上后system.gc()将不会触发gc。
3. 但是,如果完全不允许手动调用gc,
* 使用了NIO或者NIO框架(Mina/Netty)
* 使用了DirectByteBuffer分配字节缓冲区
* 使用了MappedByteBuffer做内存映射
以上情况下的堆外内存又无法回收,所以,才提到了用ExplicitGCInvokesConcurrent参数来替代DisableExplicitGC (这个关系让我一直疑问很久,究竟为什么要用ExplicitGCInvokesConcurrent参数来替代DisableExplicitGC,网上的发部分言论都在这么说,但是没有人清楚明白的说明清楚为什么! 而这才是最重要的),当然,是要在使用CMS做full GC的时候,才能使用这个参数
但是,到此,我还是不清楚ExplicitGCInvokesConcurrent的好处在哪,为什么可以替代DisableExplicitGC ,继续寻找后,发现了这篇文章:
http://breezylee.iteye.com/blog/2043056
里面有这么一段话:
3、-XX:+ExplicitGCInvokesConcurrent 或 -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses
C++代码
跟上面的第一个例子的-XX:+DisableExplicitGC一样,这两个参数也是用来改变System.gc()的默认行为用的;不同的 是这两个参数只能配合CMS使用(-XX:+UseConcMarkSweepGC),而且System.gc()还是会触发GC的,只不过不是触发一个 完全stop-the-world的full GC,而是一次并发GC周期(注:一次并发周期其实就是在CMS下的一次gc,CMS只能用在full gc 中,所以,也是一次full gc 只不过效率比较高罢了)。
CMS GC周期中也会做reference processing。所以如果用这两个参数的其中一个,而不是用-XX:+DisableExplicitGC的话,就避开了由full GC带来的长GC pause,同时NIO direct memory的OOM也不会那么容易发生。
总结:到此,我们至少可以明白两个问题:
1. ExplicitGCInvokesConcurrent用途的由来。
2. ExplicitGCInvokesConcurrent本身的功能:其实,也是触发full gc 只不过在CMS在full gc 效率比较高。