热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

JavaGC专家系列2:Java垃圾回收的监控

这是”成为GC专家系列”文章的第二篇。在第一篇理解Java垃圾回收中我们学习了几种不同的GC算法的处理过程,GC的工作方式,新生代与老年代的区别。到目前为止,你应该已经了解了JDK7中的5种GC类型,以及每种GC对性能的影响。
在本篇中,我将介绍JVM在真实环境中如何运行GC的。

什么是GC监控

GC监控 指的是在运行时跟踪JVM运行GC的过程。例如,通过GC监控,我们能找出:

  1. 何时新生代的对象会被移动到老年代,有多少对象被移到了老年代。
  2. 何时stop-the-world发生以及持续时间。

通过GC监控,能发现JVM是否在有效的运行GC以及是否需要额外的GC调优。基于这些信息,我们可以通过优化应用或者改变GC运行方式(GC调优),从而提高应用性能。

如何做GC监控

GC监控的方式很多,区别在于GC操作信息的展示会有所不同。GC是由JVM触发,因为GC监控工具展示的信息都是由JVM提供,所以不管使用哪种方式做GC监控,最终获取的信息都是一致的。因此,没有必要深入学习每种GC监控工具,只需要花些时间学习每种工具的使用方法,能够在不同的场合选择合适的工具即可。

因为JVM规范没有要求暴露GC信息的标准方法,所以下面列出的工具或JVM选项并不能适用于所有不同的JVM实现。在下面的介绍中都是基于Hotspot JVM(Oracle JVM)进行。因为NHN使用的是Oracle(Sun) JVM,所以在使用以下工具或JVM选项时并不会太困难。

首先,GC监控工具根据访问接口和方式不同分为CUIGUI。经典的CUI 工具可以使用一个单独的CUI应用jstat,也可以在运行JVM时通过提供”-verbosegc“选项来实现。

GUI GC监控工具通过单独的GUI应用来实现,后面会介绍三个常用的GUI GC工具:jconsole, jvisualvm和Visual GC。

下面开始学习每一种GC监控方法:

jstat

jstat是Hotspot JVM内置的监控工具。Hotspot JVM还内置了其他监控工具如jpsjstatd。有时候需要这三种工具一起来监控Java应用的运行。

jstat 不只提供GC操作的相关信息,也还提供类加载和即时编译器相关的操作信息。尽管如此,本文我们只会涉及jstat提供的GC操作相关的功能。

jstat 位于$JDK_HOME/bin目录,如果java或javac命令能够正常运行,jstat命令也应该能够运行。

你可以在命令行中尝试一下:

$> jstat –gc  $ 1000

S0C       S1C       S0U    S1U      EC         EU          OC         OU         PC         PU         YGC     YGCT    FGC      FGCT     GCT
3008.0   3072.0    0.0     1511.1   343360.0   46383.0     699072.0   283690.2   75392.0    41064.3    2540    18.454    4      1.133    19.588
3008.0   3072.0    0.0     1511.1   343360.0   47530.9     699072.0   283690.2   75392.0    41064.3    2540    18.454    4      1.133    19.588
3008.0   3072.0    0.0     1511.1   343360.0   47793.0     699072.0   283690.2   75392.0    41064.3    2540    18.454    4      1.133    19.588

$>

如上所示,真实的内存各部分数据情况按以下各列顺序列出:

SOC        S1C        S0U        S1U        EC        EU        OU        PC

vmid(虚拟机id: Virtual Machine ID),见名示意,表示VM的ID。运行在本地或远程的虚拟机都可以通过vmid指定。运行在本地虚拟机上的Java应用的vmid又称为lvmid(Local vmid),通常与PID相同。虽然可以通过ps命令或Windows的任务管理器查看PID的值从而得到lvmid,但更推荐使用jps,因为PID和lvmid之间并不总是一一对应。jps表示Java PS。正如ps命令可以看到PIDs和进程名,通过jps可以看到vmids和main方法信息。

通过jps找到你要监控的Java应用的vmid,然后作为jstat的参数即可。如果多个WAS实例运行在同一设备上时,如果只使用jps命令只能找到引导程序的信息。这时候就要ps -ef | grep java命令和jps命令一起使用。

GC性能数据需要持续观察,因此在运行jstat时需要定时输出GC的监控信息。

举例来说:运行jstat -gc 1000(or 1s)将会每隔1s在控制台上输出一次GC数据。jstat -gc 1000 10将会每隔1s输出一次GC数据,总共输出10次。

与GC相关的选项除了-gc,还有其他一些,如下表所示:

选项名称 描述
gc 输出堆空间上各分区当前的大小及使用量(Ede, Survivor, Old等),GC执行的总次数以及累积消耗的执行时长。
gccapacity 输出堆空间上各分区的最小和最大容量,当前大小,每个区上的GC执行次数(不输出当前使用量和累积的GC耗时)。
gccause 除了输出 -gcutil提供的信息外,还会输出最后一次GC和当前GC的原因。
gcnew 新生代上的GC性能数据。
gcnewcapacity 新生代容量的统计信息。
gcold 老年代的GC性能数据。
gcoldcapacity 老年代容量的统计信息。
gcpermcapacity 持久代(方法区)上的统计信息。
gcutil 以%的格式输出每个分区的使用量。同时也会输出GC执行的总次数及累积耗时。

如果只关心GC频率,通常使用-gcutil(或者 -gccause), -gc, -gccapacity即可。

  • -gcutil 用于检测各区上的使用量,GC执行次数以及累积耗时,
  • -gccapacity 和其他的几个选项可用于输出实际已分配的内存大小。

使用-gc选项的输出如下:

S0C         S1C    …    GCT
1248.0     896.0    …    1.246
1248.0      896.0    …    1.246
…         …        …    …

给jstat指定不同的选项会列出不同的列,如下列所示。表格右侧列出了会输出此信息的jstat选项。

数据列 描述 支持的jstat 选项
S0C Survivor0的当前容量 -gc
-gccapacity
-gcnew
-gcnewcapacity
S1C S1的当前容量 -gc
-gccapacity
-gcnew
-gcnewcapacity
S0U S0的使用量 -gc
-gcnew
S1U S1的使用量 -gc
-gcnew
EC Eden区的当前容量 -gc
-gccapacity
-gcnew
-gcnewcapacity
EU Eden区的使用量 -gc
-gcnew
OC old区的当前容量 -gc
-gccapacity
-gcnew
-gcnewcapacity
OU old区的使用量 -gc
-gcnew
PC 方法区的当前容量 -gc
-gccapacity
-gcold
-gcoldcapacity
-gcpermcapacity
PU 方法区的使用量 -gc
-gcold
YGC Young GC次数 -gc
-gccapacity
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-gccause
YGCT Young GC累积耗时 -gc
-gcnew
-gcutil
-gccause
FGC Full GC次数 -gc
-gccapacity
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-gccause
FGCT Full GC累积耗时 -gc
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-gccause
GCT GC总的累积耗时 -gc
-gcold
-gcoldcapacity
-gccapacity
-gcpermcapacity
-gcutil
-gccause
NGCMN 新生代最小容量 -gccapacity
-gcnewcapacity
NGCMX 新生代最大容量 -gccapacity
-gcnewcapacity
NGC 新生代当前容量 -gccapacity
-gcnewcapacity
OGCMN 老年代最小容量 -gccapacity
-gcoldcapacity
OGCMX 老年代最大容量 -gccapacity
-gcoldcapacity
OGC 老年代当前容量 -gccapacity
-gcoldcapacity
PGCMN 方法区最小容量 -gccapacity
-gcpermcapacity
PGCMX 方法区最大容量 -gccapacity
-gcpermcapacity
PGC 方法区当前容量 -gccapacity
-gcpermcapacity
PC 方法区的当前容量 -gccapacity
-gcpermcapacity
PU 方法区使用量 -gccapacity
-gcold
LGCC 上一次GC发生的原因 -gccause
GCC 当前GC发生的原因 -gccause
TT 存活阀值,如果对象在新生代移动次数超过此阀值,则会被移到老年代 -gcnew
MTT 最大存活阀值,如果对象在新生代移动次数超过此阀值,则会被移到老年代 -gcnew
DSS survivor区的理想容量 -gcnew

表格中容量数量单位为:KB

jstat的优点在于不管是本地还是远程Java应用,你都可以通过jstat命令查看GC操作相关的数据,并通过控制台输出这些信息。在使用-gcutil选项时,会输出如下字段的信息。在做GC调优时,尤其要关注YGC, YGCT, FGC, FGCTGCT的数据变化。

S0      S1       E        O        P        YGC    YGCT     FGC    FGCT     GCT
0.00    66.44    54.12    10.58    86.63    217    0.928     2     0.067    0.995
0.00    66.44    54.12    10.58    86.63    217    0.928     2     0.067    0.995
0.00    66.44    54.12    10.58    86.63    217    0.928     2     0.067    0.995

这些信息非常重要,它统计了GC运行时的耗时情况,能反映出GC的性能指标。

在上例中,YGC是217次, YGCT为0.928,平均下来每次young GC耗时4ms(0.004 s)。同样可算出full GC的平均耗时为33ms。

然而平均值对发现实现的GC问题并没有太大的帮助,因为每次GC耗时通常会有巨大的偏差(也就是说,如果full GC的平均值为0.067s,可能意味着其中一次GC耗时1ms,而另外一次持续134ms)。为了能观察每次GC的独立耗时而非平均值,更好的方式是使用-verbosegc

-verbosegc

-verbosegc 是运行Java应用时的一个JVM选项。jstat可以监控任何JVM应用而无需指定启动参数,-verbosegc去要在开启应用时就指定好,所以看起来-verbosegc并不是一个必要的选项(因为可以使用jstat完成相同工作)。然而当GC发生时-verbosegc的输出信息更容易理解,这对于监控烦杂的GC信息却大于益处。

jstat -verbosegc
监控目标 可输出日志到终端上的Java应用或者能通过jstatd连接到网络的远程Java应用 在启动JVM时指定了-verbosegc 参数的Java应用
输出信息 堆状态(使用量、最大容量、GC次数及累积耗时等) 每次GC前后新生代和老年代的容量变化及GC耗时
输出时机 任何指定的时间 任何GC发生时
优势 方便连续观察堆大小的变化 观察单次GC对系统的影响

在使用-verbosegc时还可同时指定以下附加选项:

  • -XX:+PrintGCDetails
  • -XX:+PrintGCTimeStamps
  • -XX:+PrintHeapAtGC
  • -XX:+PrintGCDateStamps(JDK6U4引入的选项)

如果只是指定了-verbosegc选项,则默认会同时指定-XX:+PrintGCDetails。另外,-verbosegc的附加选项都可以组合使用。

使用-verbosegc后,当有minor GC发生时,输出的数据格式如下:

[GC [:  -> ,  secs]  -> ,  secs]
字段 含义
Collector 使用的收集器
starting occupancy1 GC发生前的新生代大小
ending occupancy1 GC后新生代的大小
pause time1 执行minor GC时Java应用停顿的时长
starting occupancy3 GC发生前堆空间总大小
ending occupancy3 GC发生后堆空间总大小
pause time3 执行总体GC(包括Full GC)时Java应用停顿时长

下面是一个Full GC输出的例子:

[Full GC [Tenured: 3485K->4095K(4096K), 0.1745373 secs] 61244K->7418K(63104K), [Perm : 10756K->10756K(12288K)], 0.1762129 secs] [Times: user=0.19 sys=0.00, real=0.19 secs]

如果使用了[CMS回收算法](),CMS相关信息也会紧接着提供出来。

因为-verbosegc选项可以把每次GC发生时的信息都以log方式输出,所以很容易观察GC操作关后heap使用率的变化情况。

(Java) VisualVM + Visual GC

Java Virsual VM是Oracle JDK提供的一个GUI式的图表/监控工具。

Java GC专家系列2:Java 垃圾回收的监控

图1:VirsualVM 界面

与内置在JDK中的版本不同,你可以在网站上单独下载Virsual VM。方便起见,JDK内置的版本称为Java VirsualVM(jvisualvm),从网站上单独下载的称为Virsual VM(visualvm)。二者之间的特性并不完全一致,在一些方面(例如安装插件等)会有细微的差别。就我个人而言,更偏向于使用单独下载的Virsual VM。

启动Visual VM后,如果你左侧面板上选择了希望监控的应用,就会看到”Monitoring”一栏。从Monitoring栏中可以获得关于GC和内存堆的基本信息。

尽管能通过Visual VM的基本特性得到GC的基本状态,但并不能像使用jstat-verbosegc一样获得更详细的信息。

如果想得到像jstat一样的详细信息,则需要安装相应的Virsual VM插件。可以在Tools菜单里获取Virsual GC插件。

Java GC专家系列2:Java 垃圾回收的监控

图2:Virsual GC安装界面

通过Virsual GC,可以以更直观的方式获得jstatd提供的信息。

Java GC专家系列2:Java 垃圾回收的监控

图3:Virsual GC运行界面

HPJMeter

HPJMeter是一个分析-verbosegc输出结果的便捷工具。如果把Visual GC看作是jstat的GUI版本,那么HPJMeter则是-verbosegc的GUI版本。话说回来,GC分析只是HPJMeter提供的众多特性之一。HPJMeter是HP公司开发的一款性能监控工具,可以使用在HP-UX,Linux和MS Windows上。

起初,只是一款叫做HPTune的工具提供GUI的方式分析-verbosegc。自从HPJMeter 3.0开始便集成了HPTune,因此无需再单独下载HPTune。

在应用运行过程中,-verbosegc的输出结果可以重定向到一个单独的文件中。

可以通过HPJMeter打开该文件,然后使用直观的GUI界面便捷的分析GC数据。

Java GC专家系列2:Java 垃圾回收的监控

图4:HPJMeter

推荐阅读
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • 近年来,大数据成为互联网世界的新宠儿,被列入阿里巴巴、谷歌等公司的战略规划中,也在政府报告中频繁提及。据《大数据人才报告》显示,目前全国大数据人才仅46万,未来3-5年将出现高达150万的人才缺口。根据领英报告,数据剖析人才供应指数最低,且跳槽速度最快。中国商业结合会数据剖析专业委员会统计显示,未来中国基础性数据剖析人才缺口将高达1400万。目前BAT企业中,60%以上的招聘职位都是针对大数据人才的。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 无损压缩算法专题——LZSS算法实现
    本文介绍了基于无损压缩算法专题的LZSS算法实现。通过Python和C两种语言的代码实现了对任意文件的压缩和解压功能。详细介绍了LZSS算法的原理和实现过程,以及代码中的注释。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 本文介绍了数模国赛的报名参加方法,包括学校报名和自己报名的途径。同时给出了建模竞赛的建议,重在历练的同时掌握方法以及弥补自己的短板。此外,还分享了论文的结构和模型求解部分的注意事项,包括数学命题的表述规范和计算方法的原理等。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
author-avatar
mqfcu123
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有