内容来着《Java 程序员面试笔试宝典 第2版》

因为fullGC是用来清理整个堆空间—包括年轻代和永久代的,所以fullGC会造成很大的系统资源开销。因此,通常需要尽量避免fullGC操作。

下面介绍几种常见的fullGC产生的原因以及避免的方法。

(1)调用System.gc()方法会触发fullGC

因此,在编码的时候尽量避免调用这个方法。

(2)老年代(Old Generation)空间不足

由于老年代主要用来存储从年轻代转入的对象、大对象和大数组,因此,为了避免触发fullGC,应尽量做到让对象在Minor GC阶段被回收、不要创建过大的对象及数组。由于在Minor GC时,只有Survivor区放不下的对象才会被放入老年代,而此时只有老年代也放不下才会触发fullGC,因此,另外一种避免fullGC的方法如下所示:根据实际情况增大Survivor区、老年代空间或调低触发并发GC(并发垃圾回收)的比率。

(3)永久代(Permanent Generation)满永久代主要存放class相关的信息,当永久代满的时候,也会触发fullGC。为了避免这种情况的发生,可以增大永久代的空间(例如-XX:MaxPermSize=16m:设置永久代大小为16M)。为了避免Perm区满引起的fullGC,也可以开启CMS回收永久代选项(开启的选项为:-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled)。CMS利用和应用程序线程并发的垃圾回收线程来进行垃圾回收操作。

需要注意的是,Java8中已经移除了永久代,新加了一个称为元数据区的native内存区,所以,大部分类的元数据都在本地内存中分配。

什么情况会发生Full GC?如何避免频繁Full GC?