gc日志收集和分析

JVM 配置常用参数

  1. 堆参数;
  2. 回收器参数;
  3. 项目中常用配置;
  4. 常用组合;

堆参数

img

回收器参数

img

如上表所示,目前主要有串行、并行和并发三种,对于大内存的应用而言,串行的性能太低,因此使用到的主要是并行和并发两种。并行和并发 GC 的策略通过 UseParallelGC  UseConcMarkSweepGC 来指定,还有一些细节的配置参数用来配置策略的执行方式。例如:XX:ParallelGCThreads, XX:CMSInitiatingOccupancyFraction 等。 通常:Young 区对象回收只可选择并行(耗时间),Old 区选择并发(耗 CPU)。

项目中常用配置

备注:在Java8中永久代的参数-XX:PermSize 和-XX:MaxPermSize已经失效。

img

常用组合

img

一、gc日志收集

打印Gc日志的参数
打印gc详细信息

-XX:+PringGCDetails
带有距离JVM开始运行的时间戳

-XX:+PrintGCTimeStamps
带有日历时间戳

--XX:+PringGCDateStamps
指定gc日志存放文件(不指定则控制台打印)

-Xloggc:
针对高延迟问题调优HotSpot VM时,下面两个命令行选项特别有用,通过它们可以获得应用程序由于执行VM安全操作而阻塞的时间以及两个安全点操作之间应用程序运行的时间。

-XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCApplicationConcurrentTime
何谓安全操作:安全操作使JVM进入到一种状态:所有的java应用线程都被阻塞、执行本地代码的线程都被禁止返回VM执行Java代码。安全操作常用于虚拟机需要进行内部操作时,此时所有的Java线程都被显式地置于阻塞状态且不能修改Java堆的情况。

设置参数
Tomcat
$CATALINA_HOME/bin/setenv.sh文件
加入:

#opts for gc log
export CATALINA_OPTS="$CATALINA_OPTS -XX:+PrintGCDetails"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+PrintGCTimeStamps"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+PrintGCDateStamps"
export CATALINA_OPTS="$CATALINA_OPTS -Xloggc:/gc_logs/tomcat.gc.log"
当然,loggc的文件能够自给创建,目录得先创建好。

二、GC日志可视化分析工具GCeasy和GCViewer

GCeasy介绍
官网地址:https://gceasy.io/,GCeasy是一款在线的GC日志分析器,可以通过GC日志分析进行内存泄露检测、GC暂停原因分析、JVM配置建议优化等功能,而且是可以免费使用的(有一些服务是收费的)。

上节《GC日志介绍》我们介绍了各个垃圾收集器的GC日志,我们打开GCeasy的官网,上传我们的GC日志(我这里用的Parallel收集器),点击Analyze进行分析即可得到报告,得到的报告可以进行下载。由于报告内容比较多,我就捡几个主要的截个图简单说明一下,其他的可以自己看一下,而且可以自己试试不同的垃圾收集器的GC日志的分析报告有什么区别。

JVM的各个分代区域分配的内存及使用峰值的内存

 关键性能指标:吞吐量及GC暂停平均时间、最大时间、各个时间段的比例。

 

GC发生的原因、次数、时间等

 

GCViewer介绍
上面介绍了一款在线的GC日志分析器,下面介绍一个离线版的GCViewer,其最新版本为1.36,我用的就是这个版本,需要jdk1.8才可以使用,Github地址为https://github.com/chewiebug/GCViewer,下载下来之后执行 mvn clean install -Dmaven.test.skip=true 命令进行编译,编译完成后在target目录下会看到jar包,双击打开即可。

 

打开之后,点击File->Open File打开我们的GC日志,可以看到如下图,图标是可以放大缩小的,主要内容就是红线圈住的部分,里面的内容跟上面的GCeasy的比较类似,具体的可以看下GitHub中的描述。 

  

 三、系统CPU经常100%,如何定位

  1、首先要确认哪个进程占用CPU高,可以使用top命令

  2、找到之后可以继续执行top -Hp PID命令查询出占用最大的线程

  3、执行jstack命令生成线程快照信息:
  jstack -l 进程PID >jstack.log
  1

  输出之后,我们找到上面占用CPU最高的一个线程pid=11566,将其转换为16进制,得到的结果是2d2e,然后进入生成的jstack.log文件找到这个线程可以查看线程信息。

  4、上面就可以定位到了线程调用的方法了,接下来就可以去分析对应的代码寻找问题了

GC 调优目的

将转移到老年代的对象数量降低到最小; 减少 GC 的执行时间。

GC 调优策略

**策略 1:**将新对象预留在新生代,由于 Full GC 的成本远高于 Minor GC,因此尽可能将对象分配在新生代是明智的做法,实际项目中根据 GC 日志分析新生代空间大小分配是否合理,适当通过“-Xmn”命令调节新生代大小,最大限度降低新对象直接进入老年代的情况。

**策略 2:**大对象进入老年代,虽然大部分情况下,将对象分配在新生代是合理的。但是对于大对象这种做法却值得商榷,大对象如果首次在新生代分配可能会出现空间不足导致很多年龄不够的小对象被分配的老年代,破坏新生代的对象结构,可能会出现频繁的 full gc。因此,对于大对象,可以设置直接进入老年代(当然短命的大对象对于垃圾回收来说简直就是噩梦)。-XX:PretenureSizeThreshold 可以设置直接进入老年代的对象大小。

**策略 3:**合理设置进入老年代对象的年龄,-XX:MaxTenuringThreshold 设置对象进入老年代的年龄大小,减少老年代的内存占用,降低 full gc 发生的频率。

**策略 4:**设置稳定的堆大小,堆大小设置有两个参数:-Xms 初始化堆大小,-Xmx 最大堆大小。

**策略5:**注意: 如果满足下面的指标,则一般不需要进行 GC 优化:

MinorGC 执行时间不到50ms; Minor GC 执行不频繁,约10秒一次; Full GC 执行时间不到1s; Full GC 执行频率不算频繁,不低于10分钟1次。



原文地址:https://www.cnblogs.com/yuarvin/p/14817240.html