java应用fullgc时如何排查问题

Java程序经常 FullGC 时如何解决问题?


查看jvm内存使用情况,看是否存在如下特征(jvm查看工具如jmap,jhat,jprofier,zprofier等):

1)年老代是否被写满

2)持久代是否被写满

3)System.gc()是否在应用代码中被显式调用

1、如何做垃圾回收?

由于不同对象的生命周期不同,JVM垃圾回收通过分代策略来便提高回收效率。Java程序运行的过程中,会产生大量的对象,其中有些对象是与业务信息相关,比如Http请求中的Session对象、线程、Socket连接,这类对象跟业务直接挂钩,因此生命周期比较长。还有一些对象,主要是程序运行过程中生成的临时变量,

这些对象生命周期会比较短。若在不区分对象存活时间,每次垃圾回收都需要作用与整个堆空间,即每次回收都需要遍历所有存活对象,而对于生命周期较长的对象而言,这种遍历效率较低。


2、如何为对象生命周期分代?

年轻代:
对象在年轻代生成。年轻代的目标就是尽可能快速的收集生命周期短的对象。年轻代分三个区。一个Eden区,两个Survivor区(一般而言)。大部分对象在Eden区中生成。当Eden区满时,仍存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor区也满了时,从第一个Survivor区复制过来并且仍然存活的对象,将被复制“年老区(Tenured)”。

Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制来的对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor区来的对象。Survivor区总有一个是空的,另外Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存活时间,减少被放到年老代的机率。

年老代:
在年轻代中经历了N次垃圾回收后仍存活的对象,会被放到年老代中。所以年老代中存放的一般生命周期较长的对象。


持久代:
持久代用于存放静态文件,Java类、方法等。持久代对垃圾回收没有显著影响,如果应用会动态加载类,则需要设置适当的持久代空间来存放运行过程中新增的类。

3、什么情况下触发垃圾回收?
基于对象的分代处理,垃圾回收区域,时间也不一样。GC有两种类型:Scavenge GC和Full GC。

Scavenge GC
新对象生成在Eden申请内存失败时,会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并把仍存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC使用速度快、效率高的算法,使Eden能尽快空闲出来。

Full GC

年老代或持久代被写满,System.gc()在应用代码中被显式调用等会触发Full GC。Full GC对整个堆进行整理,包括Young、Tenured和Perm,所以比Scavenge GC要慢。

你可能感兴趣的:(效率小技巧)