Java GC - 监控回收行为与日志分析
1. 简介
在上一篇介绍<Java GC - 垃圾回收机制>, 本文将介绍如何监控 Javc GC 行为,同时涉及一些GUI工具的使用(虽然有些已经很老并不再更新),监控GC在于判断JVM是否在良好高效地工作并且是否需要投入性能调优(主要包括应用程序优化与JVM参数优化),关注的数据大概有:
1. Mirror GC频率、持续时间以及回收内存量。
2. Major GC频率、持续时间、回收内存量以及 stop-the-world 耗时。
3. Heap 对象分配(导出.hprof文件分析,通常比较大)
2. GC LOG 及Collector行为分析
LOG分析包含前面文章所介绍的各个GC collector的行为分析。通过加入 -XX:+PrintGCDetails 参数则可以打印详细GC信息至控制台。参数-verbose:gc也是可以,但不够详细。通过加入-XX:+PrintGCDateStamps则可以记录GC发生的详细时间。
通过加入 -Xloggc:/home/XX/gc/app_gc.log 可以把GC输出至文件,这对长时间服务器GC监控很有帮助。以下列出一些参数大致打印的信息如下:
1. -verbose:gc: [GC 72104K->9650K(317952K), 0.0130635 secs]
2. -XX:+PrintGCDetails: [GC [PSYoungGen: 142826K->10751K(274944K)] 162800K->54759K(450048K), 0.0609952 secs] [Times: user=0.13 sys=0.02, real=0.06 secs]
3. -XX:+PrintGCDetails 加上-XX:+PrintGCDateStamps 参数则打印如下:
2015-12-06T12:32:02.890+0800: [GC [PSYoungGen: 142833K->10728K(142848K)] 166113K->59145K(317952K), 0.0792023 secs] [Times: user=0.22 sys=0.00, real=0.08 secs]
可以看出,如果是想监控详细信息与GC发生时间,加上-XX:+PrintGCDateStamps -XX:+PrintGCDetails 参数会是一个比较好的选择。
首先来说明一段在各个GC中通用的字段含义说明:
1、142826K->10751K(274944K) 分别代表回收前、回收后以及总内存大小。
2、Times: user=0.46 sys=0.05, real=0.07 secs: user代表GC 需要的各个CPU总时间(各个CPU时间相加),sys代表回收器自身的行为所占用CPU时间,real则代表本次GC所耗费的真正耗时(在多核CPU中并行回收,它通常小于user) 。
2.1 Serial GC (-XX:+UseSerialGC)
下面是一段的Serial GC日志含义依次分解:
---------------------------
[GC[DefNew: 78656K->8704K(78656K), 0.0487492 secs] 135584K->80553K(253440K), 0.0488309 secs] [Times: user=0.05 sys=0.00, real=0.05 secs]
[Full GC[Tenured: 62546K->60809K(174784K), 0.1600120 secs] 85931K->60809K(253440K), [Perm : 38404K->38404K(65536K)], 0.1600814 secs] [Times: user=0.16 sys=0.00, real=0.16 secs]
---------------------------
1. 其中的DefNew代表单线程回收yong generation。
2. 紧跟后面的 78656K->8704K(78656K) 中的 78656K 代表young generation 回收前大小,8704K 代表回收后大小,括号中的78656K 代表young generation总大小(包含2个survivor)。
3. 135584K->80553K(253440K) 则代表整个Heap(young+old)的变化与总量,含义参照前面所述(Perm也一样)。
4. Full GC 即代表 major GC, Tenured: 62546K->60809K(174784K)则表示 old generation变化及总量
2.2 Parallel GC
Paralle GC 通过加入参数 -XX:+UseParallelGC 来指定(很多服务器默认不需要加这参数就默认使用该GC collector -- 通过判断配置来决定),通过再加入 -XX:+UseParallelOldGC 使得 Full GC也启用并行,但在(http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html)有如下介绍:
-XX:-UseParallelGC:Use parallel garbage collection for scavenges. (Introduced in 1.4.1)
-XX:-UseParallelOldGC:Use parallel garbage collection for the full collections. Enabling this option automatically sets -XX:+UseParallelGC. (Introduced in 5.0 update 6.)
如想详细查询是否真正自动启用(还是不加入-XX:+UseParallelOldGC有什么细微区别) 则可查看 Open JDK 参考实现来确定,本文不做详细分析,所以加上-XX:+UseParallelGC -XX:+UseParallelOldGC 会是个保险的选择。下面附上一段Open JDK 7的路径为:
hotspot/src/share/vm/runtime/arguments.cpp 部分源码,估计会有些帮助:
void Arguments::set_parallel_gc_flags() {
assert(UseParallelGC || UseParallelOldGC, "Error");
// If parallel old was requested, automatically enable parallel scavenge.
if (UseParallelOldGC && !UseParallelGC && FLAG_IS_DEFAULT(UseParallelGC)) {
FLAG_SET_DEFAULT(UseParallelGC, true);
}
// If no heap maximum was requested explicitly, use some reasonable fraction
// of the physical memory, up to a maximum of 1GB.
if (UseParallelGC) {
FLAG_SET_ERGO(uintx, ParallelGCThreads,
Abstract_VM_Version::parallel_worker_threads());
// If InitialSurvivorRatio or MinSurvivorRatio were not specified, but the
// SurvivorRatio has been set, reset their default values to SurvivorRatio +
// 2. By doing this we make SurvivorRatio also work for Parallel Scavenger.
// See CR 6362902 for details.
if (!FLAG_IS_DEFAULT(SurvivorRatio)) {
if (FLAG_IS_DEFAULT(InitialSurvivorRatio)) {
FLAG_SET_DEFAULT(InitialSurvivorRatio, SurvivorRatio + 2);
}
if (FLAG_IS_DEFAULT(MinSurvivorRatio)) {
FLAG_SET_DEFAULT(MinSurvivorRatio, SurvivorRatio + 2);
}
}
if (UseParallelOldGC) {
// Par compact uses lower default values since they are treated as
// minimums. These are different defaults because of the different
// interpretation and are not ergonomically set.
if (FLAG_IS_DEFAULT(MarkSweepDeadRatio)) {
FLAG_SET_DEFAULT(MarkSweepDeadRatio, 1);
}
if (FLAG_IS_DEFAULT(PermMarkSweepDeadRatio)) {
FLAG_SET_DEFAULT(PermMarkSweepDeadRatio, 5);
}
}
}
if (UseNUMA) {
if (FLAG_IS_DEFAULT(MinHeapDeltaBytes)) {
FLAG_SET_DEFAULT(MinHeapDeltaBytes, 64*M);
}
}
}
--------------------------
[GC [PSYoungGen: 88524K->10728K(274944K)] 133505K->61187K(450048K), 0.0374438 secs] [Times: user=0.08 sys=0.00, real=0.04 secs]
[Full GC [PSYoungGen: 10728K->0K(274944K)] [ParOldGen: 50459K->50210K(175104K)] 61187K->50210K(450048K) [PSPermGen: 38656K->38643K(77312K)], 0.3787131 secs] [Times: user=0.98 sys=0.02, real=0.38 secs]
--------------------------
1. PSYoungGen 代表并行回收 young generation
2. ParOldGen 代表并行回收 old generation.
3. PSPermGen 代表并行回收 Permanent generation. 其他的参数与前面解释的类似。
2.3 CMS GC
CMS GC相对来说比较复杂,通过使用 -XX:+UseConcMarkSweepGC 参数在指定,但是一般情况需要更多的其他参数来保证它能比较好地达到我们的低延时目的,下面就部分常用参数做介绍:
-XX:+CMSIncrementalMode 采用增量式的标记方式,减少标记时应用停顿时间
-XX:+CMSParallelRemarkEnabled 启用并行标记
-XX:CMSInitiatingOccupancyFraction=70 Old generation消耗比例达到多少时进行回收,通常配置60-80之间
-XX:CMSFullGCsBeforeCompaction=1 多少次Full GC 后压缩old generation一次
-XX:+UseCMSInitiatingOccupancyOnly
-XX:+ScavengeBeforeFullGC Old generation GC前对young generation GC一次,默认开启。
-XX:+CMSScavengeBeforeRemark CMS remark之前进行一次young generation GC
关于CMSFullGCsBeforeCompaction 的参数影响在Open JDK中如下判断:
*should_compact =
UseCMSCompactAtFullCollection &&
((_full_gcs_since_conc_gc >= CMSFullGCsBeforeCompaction) ||
GCCause::is_user_requested_gc(gch->gc_cause()) ||
gch->incremental_collection_will_fail(true /* consult_young */));
关于UseCMSInitiatingOccupancyOnly 参数的详细解释如下:
-XX:+UseCMSInitiatingOccupancyOnly instructs the HotSpot VM to always use the -XX:CMSInitiatingOccupancyFraction as the occupancy of the old generation space to initiate a CMS cycle.
If -XX:+UseCMSInitiatingOccupancyOnly is not used, the HotSpot VM uses the -XX:CMSInitiatingOccupancyFraction as the occupancy percentage to start only the first CMS cycle. It then attempts to adaptively adjust when to start the CMS cycle for subsequent CMS cycles, that is, it no longer uses the specified -XX:CMSInitiatingOccupancyFraction after the first CMS cycle
下面为一个可参考的CMS GC配置,根据应用的不同用途做相应修改(下面打印了GC LOG):
------------------------------------------------------
JAVA_OPTS="
-DappName=XXX
-server
-Xms10g -Xmx10g
-XX:NewSize=4g -XX:MaxNewSize=4g
-XX:PermSize=256m -XX:MaxPermSize=256m
-XX:+UseConcMarkSweepGC
-XX:+CMSIncrementalMode -XX:+CMSParallelRemarkEnabled
-XX:CMSInitiatingOccupancyFraction=70 -XX:CMSFullGCsBeforeCompaction=1
-XX:+UseCMSInitiatingOccupancyOnly
-XX:+ScavengeBeforeFullGC -XX:+CMSScavengeBeforeRemark
-XX:+PrintGCDateStamps -verbose:gc -XX:+PrintGCDetails -Xloggc:/home/XX/gc/XX_gc.log
-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=10M
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/XX/dump_OOME.hprof
-XX:+DisableExplicitGC
"
-----------------------------------------------------
下面使用一段LOG 作为 CMS GC行为:
--------------------------------
[GC [ParNew: 5033216K->629120K(5662336K), 19.9680140 secs] 5033216K->2091720K(11953792K), 19.9682480 secs] [Times: user=119.82 sys=14.07, real=19.97 secs]
[GC [1 CMS-initial-mark: 1462600K(6291456K)] 4404491K(11953792K), 3.6824630 secs] [Times: user=3.67 sys=0.01, real=3.69 secs]
[CMS-concurrent-mark-start]
[[ParNew: 5662336K->629120K(5662336K), 6.8885140 secs] 7124936K->4366353K(11953792K), 6.8886670 secs] [Times: user=136.94 sys=0.92, real=6.89 secs]
[CMS-concurrent-mark: 2.053/75.039 secs] [Times: user=192.12 sys=3.19, real=75.04 secs]
[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 6.159/6.274 secs] [Times: user=7.53 sys=0.30, real=6.28 secs]
[CMS-concurrent-abortable-preclean-start]
[CMS-concurrent-abortable-preclean: 10.680/10.681 secs] [Times: user=12.77 sys=0.43, real=10.68 secs]
[GC[YG occupancy: 3043648 K (5662336 K)] [GC [ParNew: 3043648K->629120K(5662336K), 1.5345480 secs] 6780882K->4985422K(11953792K), 1.5346490 secs] [Times: user=30.72 sys=0.27, real=1.53 secs]
[Rescan (parallel) , 0.1900960 secs] [weak refs processing, 0.0000460 secs] [scrub string table, 0.0008680 secs] [1 CMS-remark: 4356302K(6291456K)] 4985422K(11953792K), 1.7259240 secs] [Times: user=34.88 sys=0.27, real=1.72 secs]
[CMS-concurrent-sweep-start]
[CMS-concurrent-sweep: 3.379/3.380 secs] [Times: user=4.05 sys=0.13, real=3.38 secs]
[CMS-concurrent-reset-start]
[CMS-concurrent-reset: 0.030/0.030 secs] [Times: user=0.02 sys=0.01, real=0.03 secs]
---------------------------------
默认情况下Full GC之前会进行一次 Mirror GC,日志中的第一行则是,含义和前面的描述一样,不再赘述。
其他的则是CMS GC 的各个周期(在前一篇文章中有描述),其中只在 CMS-remark阶段应用暂停时间最长,但相对Parallel GC来说它相对会短些。
3. GC监控工具
GC 监控工具有JDK自带的工具和第三方分析工具,同时包含命令行与GUI工具
附: jstack 命令可以查询当前应用线程状态,可用于判断是否存在死锁、线程等待原因等问题。
3.1 jmap
jmap 有几项参数,直接执行jmap命令可打印这些选项,下面列出 -heap 参数打印情况(关键点粗体字标出):
--------------------------------
Server compiler detected.
JVM version is 24.79-b02
using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 2147483648 (2048.0MB)
NewSize = 1310720 (1.25MB)
MaxNewSize = 348913664 (332.75MB)
OldSize = 5439488 (5.1875MB)
NewRatio = 2
SurvivorRatio = 8
PermSize = 67108864 (64.0MB)
MaxPermSize = 268435456 (256.0MB)
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 80543744 (76.8125MB)
used = 13761040 (13.123550415039062MB)
free = 66782704 (63.68894958496094MB)
17.08517547930228% used
Eden Space:
capacity = 71630848 (68.3125MB)
used = 4848144 (4.6235504150390625MB)
free = 66782704 (63.68894958496094MB)
6.768234825308783% used
From Space:
capacity = 8912896 (8.5MB)
used = 8912896 (8.5MB)
free = 0 (0.0MB)
100.0% used
To Space:
capacity = 8912896 (8.5MB)
used = 0 (0.0MB)
free = 8912896 (8.5MB)
0.0% used
concurrent mark-sweep generation:
capacity = 178978816 (170.6875MB)
used = 54910688 (52.366912841796875MB)
free = 124068128 (118.32058715820312MB)
30.679992876922373% used
Perm Generation:
capacity = 67108864 (64.0MB)
used = 37996544 (36.236328125MB)
free = 29112320 (27.763671875MB)
56.6192626953125% used
17968 interned Strings occupying 2174744 bytes.
--------------------------------
下面dump一份heap分配情况:
jmap -dump:format=b,file=d:/test.hprof 7880
其中 7880为 PID,导出的文件可使用Memory Analyzer, jvisualvm, jprofile等工具打开
3.2 jhat
如果你导出的 hprof 文件很大不方便下载本地分析,可以使用 jhat 启动HTTP Server的后可以使用浏览器访问,
例如:执行 jhat d:/test.hprof 后开启 7000 端口提供HTTP服务,使用浏览器即可访问:
---------------------------
Snapshot read, resolving...
Resolving 2049558 objects...
Chasing references, expect 409 dots
...................................
Eliminating duplicate references...
...................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.
---------------------------
注:如果导出的文件很大,则需要开启更多的内存空间,使用 -J-Xmx5g 命令则开启最大5G。
3.3 jstat (jstatd) & jvisualvm
jstat用于实时监测 GC情况,如PID为7880的应用监测,每 1000毫秒打印一次:
---------------------------
jstat -gc 7880 1000
S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT
8704.0 8704.0 8704.0 0.0 69952.0 14761.0 277100.0 181950.8 65536.0 37705.5 60 2.946 35 1.285 4.231
8704.0 8704.0 8704.0 0.0 69952.0 14763.0 277100.0 181950.8 65536.0 37705.5 60 2.946 35 1.285 4.231
---------------------------
如果开启 jstatd 则可远程使用 jvisualvm 的图形化监控.
1. 首先需要配置一个policy文件,内容如下( 假设名称为 tools.policy,根据安装路径不一进行相应修改 ):
grant codebase "file:/usr/java/jdk1.7.0_79/lib/tools.jar" {
permission java.security.AllPermission;
};
2. 然后启动jstatd服务,后面的IP地址为该服务绑定的地址:
jstatd -J-Djava.security.policy=/home/XXX/tools.policy -J-Djava.rmi.server.hostname=192.168.X.X
3. 在jvisualvm中添加 Remote,输入IP新建主机后右键添加 jstatd connection,稍等片刻即可连接,如下图:
注:需要在 TOOLS->PLUGINs 中安装一些插件,如visual GC等才能查看一些更好的信息,如下图:
4. jconsole & jps
jconsole大部分功能在jvisualvm中存在,所以使用的概率相对较小。jps 则是打印目前主机中正在启动的JAVA应用的PID。
5. GCViewer
该工具用于统计加上参数如-XX:+PrintGCDetails -Xloggc:/home/xx.log 形成的LOG文件,从服务器上拿到文件后启动GCViewer打开,如下图:
6. Memory Analyzer
Memory Analyzer 用户分析 Heap dump 的 .hprof文件,展示目前Heap中的大对象等信息,如下图:
另外还有jProfiler,HPjmeter 等工具不再一一列出。
3. 总结
GC 分析主要点在于:
1. Mirror & Major GC 情况
2. Heap 对象分配
Java GC - 监控回收行为与日志分析的更多相关文章
- 面试官,不要再问我“Java GC垃圾回收机制”了
Java GC垃圾回收几乎是面试必问的JVM问题之一,本篇文章带领大家了解Java GC的底层原理,图文并茂,突破学习及面试瓶颈. 楔子-JVM内存结构补充 在上篇<JVM之内存结构详解> ...
- Java GC 垃圾回收算法 内存分配
垃圾回收(Garbage Collection, GC)是Java不同于c与c++的重要特性之一. 他帮助Java自动清空堆中不再使用的对象. 由于不需要手动释放内存,程序员在编程中也可以减少犯错的机 ...
- Java GC - 垃圾回收机制
1.简介 对于Java developer来说,了解JVM GC工作原理能够帮助我们开发出更优秀的应用,同时在处理JVM瓶颈时能够更加自由.在最近一年的应用开发中能体会到这些知识带来的好处,并且让我们 ...
- Android内存优化3 了解java GC 垃圾回收机制1
开篇废话 如果我们想要进行内存优化的工作,还是需要了解一下,但这一块的知识属于纯理论的,有可能看起来会有点枯燥,我尽量把这一篇的内容按照一定的逻辑来走一遍.首先,我们为什么要学习垃圾回收的机制,我大概 ...
- Android内存优化4 了解java GC 垃圾回收机制2 GC执行finalize的过程
1. finalize的作用 finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法. finalize()与C++中的析构函数 ...
- 乐字节Java|GC垃圾回收机制、package和import
本文接上一篇:乐字节Java|this关键字.static关键字.block块.本文是接着讲述JavaGC垃圾回收机制.package 和 import语句. 一.GC垃圾回收机制 GC全名:Garb ...
- 白话说java gc垃圾回收
gc是java区别于其他好几门语言(c/c++)的一个代表功能(当然也有很多可以自动管理内存的语言,如所有的脚本语言,你根本不知道内存管理这回事)! 当然,之所以要把c/c++和java相比,是因为j ...
- Android内存优化5 了解java GC 垃圾回收机制3
引言 接App优化之内存优化(序), 作为App优化系列中内存优化的一个小部分. 由于内存相关知识比较生涩, 内存优化中使用到的相关工具, 也有很多专有名词. 对Java内存管理, GC, Andro ...
- JAVA gc垃圾回收机制
一.GC概要 JVM堆相关知识 为什么先说JVM堆? JVM的堆是Java对象的活动空间,程序中的类的对象从中分配空间,其存储着正在运行着的应用程序用到的所有对象.这些对象的建立方 ...
随机推荐
- find的用法
find在Linux系统中和其它工具,如sed.awk.grep等结合起来用,非常有用. 1.列出系统中所有属于root用户的“set uid”文件 #find / -perm 4755 –uid 0 ...
- 如何用php实现文件上传与显示
首先,我们要创建一个前台页面用于操作选择文件等: <body> <div id="div1"></div> <form action=&q ...
- $.Deferred 延迟对象
一.什么是deferred对象? 开发网站的过程中,我们经常遇到某些耗时很长的javascript操作.其中,既有异步的操作(比如ajax读取服务器数据),也有同步的操作(比如遍历一个大型数组),它们 ...
- Latex: 插入数学公式
write equations align equations to left To only align one equation, you can \begin{flalign} &\te ...
- tomcat运行war包报错,找不到context-root文件
今天在部署项目的时候遇到了这个问题,查看Tomcat日志/logs/cataline.out这个文件. 里面有一句:can not open .....[context-root.xml], 进过很长 ...
- 一张图告诉你 canvas 中的 miterLimit 代表着什么
一图胜千言, 图中有一条路径path, 沿着路径描了一条宽度为 width 的边, miterLimit 代表的是, 比例 ab/ac, 其中ac的长度为 1/2 width 来看 mdn 上的描述, ...
- django-xadmin列表页filter关联对象搜索问题
环境:xadmin-for-python3 python3.5.2 django1.9.12 问题描述:Product ProductSku两个实体,ProductSku FK外键关联Product ...
- linux 升级yum对应的python
这里记录一下linux 系统升级python对yum带来影响的解决办法 很多人在使用linux系统执行python任务的时候需要升级linux系统自带的python到高级版本.具体如何升级python ...
- Dagger2学习笔记
Dagger2是第一个使用生成代码的方式实现依赖注入的框架.作为Dagger的升级版本,自然有它的优势,优先注重的是执行效率.本文着重介绍Dagger2.官方据点传送门: https://google ...
- 【操作教程】利用YCSB测试巨杉数据库性能
一.前言 巨杉数据库(SequoiaDB)是国内第一款新一代文档型分布式数据库,巨杉数据库由巨杉软件完全自主研发,拥有完全自主知识产权,不基于任何其它的开源项目.SequoiaDB数据库是为分布式存储 ...