JVM——GC分析

GC 的概念

GC是java语言的垃圾回收机制,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢。这是因为在Java虚拟机中,存在自动内存管理和垃圾清扫机制。

概括地说,该机制对JVM(Java Virtual Machine)中的内存进行标记,并确定哪些内存需要回收,根据一定的回收策略,自动的回收内存,永不停息(Nerver Stop)的保证JVM中的内存空间,防止出现内存泄露和溢出问题。

GC主要有 YoungGC,OldGC,FullGC。(还有G1中独有的Mixed GC,收集整个young区以及部分Old区)

  • YoungGC:回收Eden区,有些地方称之为Minor GC,或者简称YGC
  • OldGC:回收Old区,只单独回收Old区的只有CMS GC,且是CMS的concurrent collection模式。
  • FullGC:收集整个GC堆,也称之为Major GC。

注:如果配置了CMS垃圾回收器,那么jstat中的FGC并不表示就一定发生了FullGC,很有可能是发生了CMS GC,而且每发生一次CMS GC,jstat中的FGC就会+2**。

FullGC 触发条件

  1. 没有配置 -XX:+DisableExplicitGC的情况下System.gc()会触发FullGC;
  2. 老年代空间不足
  3. 方法区空间不足
  4. 通过Minor GC后进入老年代的平均大小大于老年代的可用内存
  5. 执行jmap histo : live 或 jmap -dump :live;

注:统计发现之前YGC的平均晋升大小比目前old gen剩余的空间大,触发CMS GC;Metaspace Space使用达到Metaspace阈值是触发CMS GC;

健康的 GC

无论是定位YoungGC,OldGC,FullGC哪一种GC,判断其是否正常主要从两个维度:GC频率和STW时间;
要得到这两个维度的值,我们需要知道JVM运行了多久,执行如下命令即可:

ps -p pid -o etime

可参考的健康的GC状况:

  1. YoungGC频率5秒/次;
  2. CMS GC频率不超过1天/次;
  3. 每次YoungGC的时间不超过30ms;
  4. FullGC频率尽可能完全杜绝;

G1&CMS时,FullGC回收算法会退化成Serial+SerialOld,即单线程串行回收,且完全STW,影响很大且STW时间完全不可预估,所以FullGC频率尽可能完全杜绝。

如何获取 GC 日志

一般情况可以通过两种方式来获取GC日志,一种是使用命令动态查看,一种是在容器中设置相关参数打印GC日志。

命令动态查看

jstat-gc 统计垃圾回收堆的行为

JVM——GC分析_2020-04-07-16-45-35.png

也可以设置间隔固定时间来打印:

jstat -gc 1262 2000 20

这个命令意思就是每隔2000ms输出1262的gc情况,一共输出20次。

更多详细内容请参考这篇文章:JVM——命令调优

GC 参数

  • -XX:+PrintGC 输出GC日志
  • -XX:+PrintGCDetails 输出GC的详细日志
  • -XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
  • -XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2017-09-04T21:53:59.234+0800)
  • -XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
  • -Xloggc:../logs/gc.log 日志文件的输出路径

Tomcat设置

我们经常在tomcat的启动参数中添加JVM相关参数,这里有一个典型的示例:

1
2
3
4
5
6
7
8
9
10
11
JAVA_OPTS="-server -Xms2000m -Xmx2000m -Xmn800m -XX:PermSize=64m -XX:MaxPermSize=256m -XX:SurvivorRatio=4

-verbose:gc -Xloggc:$CATALINA_HOME/logs/gc.log

-Djava.awt.headless=true

-XX:+PrintGCTimeStamps -XX:+PrintGCDetails

-Dsun.rmi.dgc.server.gcInterval=600000 -Dsun.rmi.dgc.client.gcInterval=600000

-XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=15"

-verbose:gc-Xloggc:$CATALINA_HOME/logs/gc.log

将虚拟机每次垃圾回收的信息写到日志文件中,文件名由file指定,文件格式是平文件,内容和-verbose:gc输出内容相同。

-Djava.awt.headless=true Headless

模式是系统的一种配置模式。在该模式下,系统缺少了显示设备、键盘或鼠标。

-XX:+PrintGCTimeStamps-XX:+PrintGCDetails

设置gc日志的格式

-Dsun.rmi.dgc.server.gcInterval=600000-Dsun.rmi.dgc.client.gcInterval=600000

指定rmi调用时gc的时间间隔

GC日志分析工具

GChisto GC Easy 詳細請訪問:Java GC 分析

如何减少GC出现的次数

  1. 对象不用时显示置null。
  2. 少用System.gc()。
  3. 尽量少用静态变量。
  4. 尽量使用StringBuffer,而不用String累加字符串。
  5. 分散对象创建或删除的时间。
  6. 少用finalize函数。
  7. 如果需要使用经常用到的图片,可以使用软引用类型,它可以尽可能将图片保存在内存中,供程序调用,而不引起OOM。
  8. 能用基本类型就不用基本类型封装类。
  9. 增大-Xmx的值。

在生产环境中,根据需要配置相应的参数来监控JVM运行情况。

推荐阅读

如何优化Java GC

教你如何成为Java的OOM Killer

文章目录
  1. 1. GC 的概念
  2. 2. FullGC 触发条件
  3. 3. 健康的 GC
  4. 4. 如何获取 GC 日志
    1. 4.1. 命令动态查看
    2. 4.2. GC 参数
    3. 4.3. Tomcat设置
  5. 5. GC日志分析工具
  6. 6. 如何减少GC出现的次数
  7. 7. 推荐阅读
|