JVM调优

    xiaoxiao2022-07-02  117

    目录

    ①堆大小的设置;②回收器的选择;③打印GC日志。

    参数设置示例:

    当一组对象生成时,内存申请过程如下:

    OOM(Out Of Memory)异常一般主要有如下2种原因:


    ①堆大小的设置;②回收器的选择;③打印GC日志。

    调优手段主要是通过 控制堆内存的各个部分的比例 和 GC策略 来实现的,下面来看看设置不合理会导致什么后果。

    1)新生代设置过小

    新生代GC次数非常频繁,增大系统消耗;导致大对象直接进入旧生代,占据了旧生代剩余空间,诱发Full GC

    2)新生代设置过大

    新生代设置过大会导致旧生代过小(堆总量是一定的),从而诱发Full GC;新生代GC耗时大幅度增加。一般来说新生代占整个堆1/3比较合适

    3)Survivor设置过小

    导致对象从eden直接到达旧生代,降低了在新生代的存活时间

    4)Survivor设置过大

    导致eden过小,增加了GC频率(eden满,GC;Survivor满,不诱发GC)。另外,通过-XX:MaxTenuringThreshold = n 来控制新生代存活时间,尽量让对象在新生代被回收

    由内存管理和垃圾回收可知,新生代和旧生代有多种GC策略和组合搭配,对开发来说是个难题,JVM提供了两种较为简单的GC策略的设置方式。

    1)吞吐量优先

    JVM以吞吐量为指标,由-XX:GCTimeRatio = n来设置

    2)暂停时间优先

    JVM以暂停时间为指标,由-XX:MaxGCPauseRatio = n来设置

    参数设置示例:

    -Xmn2g:设置年轻代大小为2G。在整个堆内存大小确定的情况下,增大年轻代会减小年老代,反之亦然。

    -XX:MaxTenuringThreshold = 7(Threshold n门槛,阈):表示一个对象如果在Survivor区,移动了7次还没有被垃圾回收就进入老年代。如果设置为0,则年轻代对象不经过Survivor区,直接进入年老代,对于需要大量常住内存的应用,这样做可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象在年轻代存活时间,增加对象在年轻代被垃圾回收的概率,减少Full GC的频率,可以在某种程度上提高服务器的稳定性。

    年轻代:Eden + Survivor(from)+ Survivor(to)

                  垃圾回收:GC

    年老代:在年轻代中经历了N次(可配置)垃圾回收后仍然存活的对象,就会被复制到年老代。因此,可以认为年老代中存放的                都是一些生命周期较长的对象。

                  垃圾回收:Full GC

    持久代:用于存放静态类型数据,如:Java class、Method等。持久代对垃圾回收没有显著影响。

    当一组对象生成时,内存申请过程如下:

    ①JVM会试图为相关Java对象在年轻代的Eden区中初始化一块内存区域。

    ②当Eden区空间足够时,内存申请结束。否则,执行下一步。

    ③JVM试图释放在Eden区中所有不活跃的对象(Young GC)。释放后若Eden空间仍然不足以放入新对象,JVM则试图将部分Eden区中的活跃对象放入Survivor区。

    ④Survivor区被用来作为Eden区及年老代的中间交换区域。当年老代空间足够时,Survivor区中存活了一定次数的对象会被转移到年老代。

    ⑤当年老代空间不够时,JVM会在年老代进行完全的垃圾回收(Full GC)。

    ⑥Full GC后,若Survivor区及年老代仍然无法存放从Eden区复制过来的对象,则会导致JVM无法再Eden区为新生成的对象申请内存,即出现OOM,即Out Of Memory

    OOM(Out Of Memory)异常一般主要有如下2种原因:

    ①年老代溢出,表现为java.lang.OutOfMemoryError:Javaheapspace

    这是最常见的情况,产生原因是:设置的内存参数Xmx过小或程序的内存泄露及使用不当问题。

    例如:循环上万次的字符串处理、创建上千万个对象、在一段代码内申请上百M甚至上G的内存。还有的时候虽然不会报内存溢出,却会使系统不间断的垃圾回收,也无法处理其他请求。这种情况下除了检查程序、打印堆内存等方法排查,还可以借助一些内存分析工具,如:MAT

    ②持久代溢出,表现为java.lang.OutOfMemoryError:PermGenspace

    通常是由于持久代设置过小,动态加载了大量Java类而导致溢出,解决方法为由将参数-XX:MaxPermSize调大(一般245M能满足绝大多数应用程序需求)。将部分Java类放到容器共享区(例如:Tomcat share lib)去加载的办法也是一个思路,但前提是容器里部署了多个应用,且这些应用有大量的共享类库。

    以上知识是Jdk1.8以前,Jdk1.8去除了Perm持久区。

     

     --------------------------------------------以上内容节选自《深入分析Java Web技术内幕》一书

    最新回复(0)