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对象的活动空间,程序中的类的对象从中分配空间,其存储着正在运行着的应用程序用到的所有对象.这些对象的建立方 ...
随机推荐
- [0] AssemblyInfo.cs文件介绍
AssemblyInfo.cs文件:包含程序版本.信息.版权的属性文件 先介绍AssemblyInfo.cs文件中的程序集属性 内容: using System.Reflection;using Sy ...
- 静态库 .a 转成共享库 .so
.a 是有一系列 .o 文件通过 ar 程序打包在一起的静态库,要把它转成动态库只需先解开,生成一堆 .o 文件,再通过编译器(比如 gcc 或 ifort,视具体情况而定)编成动态库即可. ar - ...
- IBM芯片新功能:诊断癌症
治愈任何疾病的最好方法是什么?-------------- 当然是把它扼杀在摇篮里. "早发现早治疗"已经是老生常谈,但要准确监测疾病又谈何容易?不过现在,IBM这枚小小的芯片就能 ...
- scanner--inputstreamreader--console对比
1 JDK 1.4 及以下版本读取的方法 JDK 1.4 及以下的版本中要想从控制台中输入数据只有一种办法,即使用System.in获得系统的输入流,再桥接至字符流从字符流中读入数据.示例代码如下: ...
- jquery取出所有包含class='engineer_val'的值
$(".engineer_val").each(function(){ //jquery取出所有包含class='engineer_val'的值 $(); });
- C语言之复杂链表的复制(图示详解)
什么是复杂链表? 复杂链表指的是一个链表有若干个结点,每个结点有一个数据域用于存放数据,还有两个指针域,其中一个指向下一个节点,还有一个随机指向当前复杂链表中的任意一个节点或者是一个空结点.今天我们要 ...
- SQl server 2012安装问题 error code 0x858C001b 解决方法
英文版系统安装中文版sql server的缘故,改安装英文版即可.
- Linux程序设计之shell程序设计
看了<linux程序设计(第4版)>(作者:Neil Matthew ,Richard Stones ,陈建 ,宋健建译).做个笔记,以备后面查看. 首先,清楚几个概念. shell编程属 ...
- 算法——蛮力法之选择排序和冒泡排序c++实现
这次实现的是蛮力法中的两个例子,选择排序法和冒泡排序法,使用的编译环境是vs2013,下面对这两个算法做一个简单介绍,然后是两个算法的c++实现代码. 选择排序法比较的范围是整个列表,每次扫描结束找出 ...
- spring +springmvc+mybatis组合web.xml文件配置
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://w ...