java gc专家系列2:java 垃圾回收的监控-mile米乐体育

这是”成为gc专家系列”文章的第二篇。在第一篇理解java垃圾回收中我们学习了几种不同的gc算法的处理过程,gc的工作方式,新生代与老年代的区别。到目前为止,你应该已经了解了jdk 7中的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式的图表/监控工具。



图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插件。



图2:virsual gc安装界面

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



图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数据。



图4:hpjmeter

下章介绍

本章作为gc调优的铺垫,着重于介绍了如何进行gc信息监控。一般情况我比较建议先使用jstat观察gc操作,当发现有比较耗时的gc后,再通过-verbosegc来分析gc数据。因此gc调优的一般过程就是分析和对比使用不同gc选项后-verbosegc输出结果的变化。下章将会通过真实案例来介绍进行gc调优的最佳选项。

作者:sangmin lee, 性能实验室高级工程师,nhn公司

展开全文
内容来源于互联网和用户投稿,文章中一旦含有米乐app官网登录的联系方式务必识别真假,本站仅做信息展示不承担任何相关责任,如有侵权或涉及法律问题请联系米乐app官网登录删除

最新文章

网站地图