JVM 优化实战[通俗易懂]

JVM 优化实战[通俗易懂]本文讲解了JVM的内存划分和分配策略,并以截图和脚本展示常用可视化和命令行工具的使用方法,完整演示了JVM优化、内存泄露排查、gc.log分析方法等。作者:王克锋 出处:https://kefeng.wang/2016/11/22/java-jvm/ 版权:自由转载-非商用-非衍生-保持署名,转载请标明作者和出处。1GC相关内存1.1内存划分1.1.1堆(Heap)存放 newM…

大家好,又见面了,我是你们的朋友全栈君。

本文讲解了 JVM 的内存划分和分配策略,并以截图和脚本展示常用可视化和命令行工具的使用方法,完整演示了 JVM 优化、内存泄露排查、gc.log 分析方法等。

作者:王克锋 
出处:https://kefeng.wang/2016/11/22/java-jvm/ 
版权:自由转载-非商用-非衍生-保持署名,转载请标明作者和出处。

1 GC相关内存

1.1 内存划分

JVM 优化实战[通俗易懂]

1.1.1 堆(Heap)

存放 new MyClass() 的对象,是GC的主要区域, 
-Xms / -Xmx 分别是堆的初始容量、最大可扩展容量,建议初始值设置为最大值,以免反复扩展或缩减的开销; 
– 新生代(Young Generation):又划分为 Eden(伊甸园,新生区), Survivor#0(幸存区S0), Survivor#1(幸存区S1) 
– 老年代(Tenured Generation)

-XX:NewRatio 是“老年代 / 新生代”的比例,默认值为 2; 
-XX:SurvivorRatio 是指 Eden/Survivor#0 的比例,而Survivor#0 与 Survivor#1 容量相同;

1.1.2 永久代(Permanent Generation)

存放类信息、常量、大对象(比如 new byte[n]对象); 
-XX:PermSize / -XX:MaxPermSize 为永久代的初始、最大容量,建议初始容量指定为最大容量; 
JDK8 中,永久代被完全的移除了,包括相关参数 -XX:PermSize / -XX:MaxPermSize。改用 Metaspace,通过参数-XX:MetaspaceSize / -XX:MaxMetaspaceSize / -XX:CompressedClassSpaceSize 设定;

1.1.3 实例解析

选项 -Xms300M -Xmx300M -XX:NewRatio=2 -XX:SurvivorRatio=8 -XX:PermSize=100M -XX:MaxPermSize=100M 含义为: 
– 永久代固定尺寸为 100M; 
– 整个堆固定尺寸为 300M,其中“老年代 / 新生代”为-XX:NewRatio=2,所以老年代为 200M,新生代为 100M; 
– 新生代总共 100M,其中“Eden / Survivor0”为-XX:SurvivorRatio=8,所以 Eden 为 80M,Survivor0=Survivor1=10M。 
官方资料:http://www.oracle.com/technetwork/articles/java/vmoptions-jsp-140102.html

1.2 JVM内存分配策略

1.2.1. 对象优先分配在 Eden

首先尝试在 Eden 分配,若 Eden 空间不足,就发起 YoungGC(简称YGC); 
– 如果幸存对象(被根对象直接或间接引用)在 SurvivorTo 能放下,则存活对象全部移入 SurvivorTo; 
– 如果幸存对象在 SurvivorTo 存放不下,则存活对象全部移入老年代; 
如果此时老年代空间不足,则发起一次 FullGC(简称FYC,整个系统停顿,老年代也参与回收); 
如果 FullGC 时空间仍然周转不过来,则报 OutOfMemoryError 并导致进程结束; 
– 如果YGC/FGC能周转过来,则新对象分配在 Eden 中;

1.2.2. 大对象直接分配在老年代

所谓的大对象是指,需要大量连续内存的 Java 对象,尤其是长字符串或数组,比如 byte[n] 对象; 
可以指定多大才算大对象(只对 Serial/ParNew 有效);

1.2.3. 长期存活对象移入老年代

经历 n 次 YGC 仍然存活的对象,下次 YGC 时将被移入老年代; 
可以设置该数值:-XX:MaxTenuringThreshold=15(默认)

1.2.4. 永久代满了也会导致 FullGC

老年代、永久代的垃圾收集是捆绑在一起的,因此无论两者谁满了,都会触发两者的FullGC。

1.2.5. 动态对象年龄判定

如果 Survivor 相同年龄对象占用空间达到一半,则大于等于该年龄的对象都移入老年代;

1.2.6. 冒险模式

JDK 6u24 之后,总是开启冒险模式(先尝试 YGC,以免 FGC 频繁); 
每次 YGC 之前,如果老年代最大连续空间,大于新生代所有对象空间之和,则 YGC 肯定成功,否则: 
– 如果老年代最大连续空间,大于历次晋升老年代的平均值,则先冒险尝试 YGC; 
– 如果老年代最大连续空间,小于历次晋升老年代的平均值,则直接 FullGC;

2 JVM优化原则

2.1 优化目标

2.1.1 尽量减少 YoungGC,以减少代码停顿

2.1.2 尽量减少 FullGC,以减少系统停顿

一天最多 FullGC 一次,最好在系统空闲期(如深夜);

2.2 优化方法

2.2.1 代码角度

缩短对象生命期,尤其是大对象

2.2.2 JVM参数角度

优化JVM参数以减少YGC/FGC次数,可替换收集器

3 服务端开启 JMX/jstatd

这两项功能必须开启,下面的可视化工具 VisualVM 要用到。

3.1 设置系统环境变量

### 下文多处用到此变量,统一维护在系统环境变量里
set JMX_HOSTNAME=192.168.214.128 ## Windows
export JMX_HOSTNAME=192.168.214.128 ## Linux
  • 1
  • 2
  • 3

3.2 开启 JMX(指定端口 1090)

需要注意的是,如果服务端 JMX 开启了修改和控制权限,此时如果不验证监控客户端的身份,那么所有用户都可以修改和控制 Tomcat 服务,所以重要的服务器应该开启用户名和密码验证。

3.2.1 准备用户验证文件

### Windows
copy/b "%JAVA_HOME%\jre\lib\management\jmxremote.password.template" "%CATALINA_BASE%\conf\jmxremote.password"
copy/b "%JAVA_HOME%\jre\lib\management\jmxremote.access" "%CATALINA_BASE%\conf\jmxremote.access"

### Linux
cp "$JAVA_HOME/jre/lib/management/jmxremote.password.template" "$CATALINA_BASE/conf/jmxremote.password"
cp "$JAVA_HOME/jre/lib/management/jmxremote.access" "$CATALINA_BASE/conf/jmxremote.access"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

jmxremote.password 用于设置各个【用户名|密码】

### $CATALINA_BASE/conf/jmxremote.password
jmxadmin    jmxpwd
  • 1
  • 2

jmxremote.access 用于设置各个【用户名|权限】

### $CATALINA_BASE/conf/jmxremote.access
jmxadmin    readwrite \
            create javax.management.monitor.*,javax.management.timer.* \
            unregister
  • 1
  • 2
  • 3
  • 4

3.2.2 修改用户验证文件权限

安全起见,JMX 限制其他用户不可读这两个用户验证文件。 
默认情况下,Windows/Linux 下分别会报如下错误: 
– 错误: 必须限制口令文件读取访问权限: %CATALINA_BASE%\conf\jmxremote.password 
– Error: Password file read access must be restricted: $CATALINA_BASE/conf/jmxremote.password

Windows下可按如下操作修改文件权限: 
– 右键单击文件 jmxremote.password,弹出菜单中选“属性”,再点“安全”/“高级”/“更改权限”/“包括可从该对象的父项继承的权限”(弹出窗口中选“删除”以删除所有访问权限); 
– 再选“添加”/“高级”/“立即查找”,选中你的用户(如 WKF-PC),点“确定”; 
– 权限项目窗口中勾选“完全控制”,点“确定”。

Linux 下则更简单:

cd $CATALINA_BASE/conf
chmod 600 jmxremote.password jmxremote.access
  • 1
  • 2

3.2.3 修改 Tomcat 启动时 JVM 选项

如果测试服务器无需开启用户验证,只需修改下面参数 authenticate=false, 并去掉 password.file 和 access.file 两个参数。

### Windows: %CATALINA_HOME%\bin\startup.bat
set JAVA_OPTS=%JAVA_OPTS% -Djava.rmi.server.hostname=%JMX_HOSTNAME% ^
    -Dcom.sun.management.jmxremote=true ^     -Dcom.sun.management.jmxremote.port=1090 ^     -Dcom.sun.management.jmxremote.ssl=false ^     -Dcom.sun.management.jmxremote.authenticate=true ^     -Dcom.sun.management.jmxremote.password.file=%CATALINA_BASE%\conf\jmxremote.password ^     -Dcom.sun.management.jmxremote.access.file=%CATALINA_BASE%\conf\jmxremote.access 
### Linux: $CATALINA_HOME/bin/startup.sh
export JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=$JMX_HOSTNAME
    -Dcom.sun.management.jmxremote=true     -Dcom.sun.management.jmxremote.port=1090     -Dcom.sun.management.jmxremote.ssl=false     -Dcom.sun.management.jmxremote.authenticate=true     -Dcom.sun.management.jmxremote.password.file=$CATALINA_BASE/conf/jmxremote.password     -Dcom.sun.management.jmxremote.access.file=$CATALINA_BASE/conf/jmxremote.access"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

3.3 开启 jstatd agent(默认端口 1099)

### $CATALINA_BASE/conf/jstatd.policy
### 可借鉴 $JAVA_HOME/jre/lib/security/java.policy
grant codeBase "file:${java.home}/../lib/tools.jar" {
    permission java.security.AllPermission;
};
  • 1
  • 2
  • 3
  • 4
  • 5
### $CATALINA_HOME/bin/jstatd.sh
### chmod +x $CATALINA_HOME/bin/jstatd.sh
#!/bin/sh 
PID=`jps | grep Jstatd | awk '{print $1}'`
if [ -n "$PID" ]; then
   echo "kill -9 $PID ..."
   kill -9 $PID
fi

jstatd -J-Djava.rmi.server.hostname=$JMX_HOSTNAME \
   -J-Djava.security.policy=$CATALINA_BASE/conf/jstatd.policy \
   -J-Xms128M -J-Xmx128M -J-XX:NewRatio=1 -J-XX:SurvivorRatio=8 -J-XX:PermSize=16M -J-XX:MaxPermSize=16M \
   < /dev/null &> $CATALINA_BASE/logs/jstatd.log &
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

3.4 配置防火墙(放行端口 1090/1099)

### /etc/sysconfig/iptables
-A INPUT -m state --state NEW -m tcp -p tcp --dport 1090 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 1099 -j ACCEPT
### 重启生效: systemctl restart iptables
  • 1
  • 2
  • 3
  • 4

4 可视化工具

4.1 JConsole

早期的 Java 故障和监控工具,现在可以由强大的 VisualVM 代替。

4.2 VisualVM

4.2.1 文档

http://m.blog.csdn.net/article/details?id=51090115 
http://docs.oracle.com/javase/8/docs/technotes/guides/visualvm/index.html

4.2.2 下载与安装

可以使用 JDK 自带的 %JAVA_HOME%\bin\jvisualvm.exe; 
也可以使用最新版本,下载方法如下: 
下载页:https://visualvm.github.io/download.html 
主程序:https://github.com/visualvm/visualvm.src/releases/download/1.3.9/visualvm_139.zip 
汉化包:https://github.com/visualvm/visualvm.src/releases/download/1.3.9/visualvm_139-ml.zip 
IDE插件:https://visualvm.github.io/idesupport.html 
主程序与汉化包解压到同一目录,最终主程序为 bin\visualvm.exe; 
IDE插件支持 Eclipse/IntelliJ IDEA,可以随着 IDE 启动。

4.2.3 安装 VisualGC 插件

http://www.oracle.com/technetwork/java/visualgc-136680.html 
VisualVM 中,点击菜单“工具”/“插件”,如下图安装: 
JVM 优化实战[通俗易懂]

有些插件不能成功安装,可下载 nbm 包再手工安装: 
https://visualvm.github.io/plugins.html 
http://visualvm.java.net/pluginscenters.html 
或者在插件设置里,修改或新增插件源(pluginscenters.html里点击后能找到),再安装。 
http://bits.netbeans.org/VisualVM/uc/release138/updates.xml 
http://bits.netbeans.org/VisualVM/uc/8u40/updates.xml 
几款有用的插件: 
– BTrace Workbench(只适用于本地应用): 用于不停止进程的情况下添加代码跟踪,入口在应用的右键菜单里; 
– KillApplication(只适用于本地应用): 用于杀掉进程,入口在应用的右键菜单里; 
– VisualVM-MBeans(本地和远程通用):类似于 JConsole 展示应用的 MBean,包括值、操作、通知等; 
– Tracer(本地和远程通用): 以时间曲线图展示多种指标,包括CPU/GC/Heap/PermGen/Classes/Threads等。

4.2.4 前提条件

对于本地应用,VisualVM 所有功能直接支持它; 
对于远程应用,VisualGC 标签页要求服务端开启 jstatd agent,其他标签页要求开启 JMX,否则会显示错误“不受此 JVM 支持”。 
对于远程应用,需要注意的是,服务端 jstatd/JMX 重启后,VisualVM 必须重启或者重建 JMX 连接,否则服务端调整在 VisualVM 中不生效。

4.2.5 添加远程主机 / JMX连接

(1)添加“远程主机”,指定远程服务器的 IP 和 jstatd 端口: 
JVM 优化实战[通俗易懂]

(2)添加“JMX 连接”,指定远程应用的 JMX 端口、用户名和密码: 
JVM 优化实战[通俗易懂]

4.2.6 监控远程应用

(1)双击左侧的“JMX 连接”(注意小图标底部有 JMX 字样),切换至“概述”标签页,可看到概述和 JVM 参数信息: 
JVM 优化实战[通俗易懂]

(2)切换至“监视”标签页,可看到 CPU、Heap、Class加载、线程等时间曲线图: 
JVM 优化实战[通俗易懂]

(3)切换至“线程”标签页,可看到各线程 CPU 耗时统计: 
JVM 优化实战[通俗易懂]

(4)切换至“抽样器”标签页,可看到热点方法耗时、主要对象占用空间统计(可用于定位内存泄露): 
JVM 优化实战[通俗易懂]

(5)切换至“VisualGC”标签页,可看到各种内存变化曲线、各GC时间点(可用于JVM参数调优): 
JVM 优化实战[通俗易懂]

4.2.7 JVM 优化实战

(1)优化前,没有明确指定各内存大小,使用 Java 默认内存大小,相当于指定为:

export JAVA_OPTS="$JAVA_OPTS -Xms52M -Xmx244M -XX:NewRatio=2
   -XX:SurvivorRatio=8 -XX:PermSize=30M -XX:MaxPermSize=1G"
  • 1
  • 2

可见 YoungGC 很频繁: 
JVM 优化实战[通俗易懂]
观察图形可得出以下优化方案: 
– 机器内存为 1G,本应用为系统唯一大应用,分给它 512M,另外 512M 预留给系统和其他应用; 
– 永久代只需 30M,可指定初始和最大值为 64M,避免反复伸缩的开销; 
– 整个堆(新生代+老年代)目前内存为 240M,可增加至 384M,指定初始和最大值都为 384M,避免反复伸缩的开销; 
– YoungGC 过于频繁,原因是 Eden 区过小。“老年代/新生代”目前比例为 -XX:NewRatio=2,看图形可知,老年代中长寿对象并不多,可缩减老年代让给新生代,所以调整 -XX:NewRatio=1; 
– “Eden / Survivor0”比值目前为 -XX:SurvivorRatio=8,暂不调整。

(2)优化后,指定 JVM 选项为:

### Linux: $CATALINA_HOME/bin/startup.sh
export JAVA_OPTS="$JAVA_OPTS -Xms384M -Xmx384M -XX:NewRatio=1 -XX:SurvivorRatio=8 -XX:PermSize=64M -XX:MaxPermSize=64M"
  • 1
  • 2
  • 3

可见 YoungGC 大幅减少: 
JVM 优化实战[通俗易懂]

(3)优化前后对比: 
优化前:YoungGC 102次,总耗时 965ms, FullGC 5次,总耗时 240ms,而且应用稳定后 YoungGC 仍然反复发生; 
优化后:YoungGC 3次,总耗时 26ms, FullGC 1次,总耗时 4ms,而且应用稳定后 YoungGC 长期未再发生; 
优化效果非常明显。

5 命令行工具(服务端)

5.1 jps(查看Java进程)

### jps -vlm | grep Bootstrap
1162 ## 进程ID
    -Xms300M -Xmx300M -XX:NewRatio=2 -XX:SurvivorRatio=8 ## -v的作用,显示 JVM 参数
    org.apache.catalina.startup.Bootstrap ## -l的作用,显示主类的全名(或JAR包路径)
    start ## -m 的作用,显示传递给主类 main() 函数的参数
  • 1
  • 2
  • 3
  • 4
  • 5

5.2 jmap/jhat(快照的生成与查看)

### 服务器上执行,生成 heapdump 快照文件
jmap -dump:live,format=b,file=tomcat.hprof 1162
sz tomcat.hprof ## 下载到个人PC

### 创建WEB服务,个人PC上可以用浏览器查看 http://localhost:8080/
### 功能较弱,以 package 分组展示,“Show heap histogram”可用于分析内存泄露。
### 也可以用 VisualVM 打开快照文件来查看
jhat -port 8080 tomcat.hprof

### jmap 更多功能
jmap -heap 1162 ## 查看堆内存划分、各区块尺寸、已用容量和比率等
jmap -histo:live 1162 ## 可用于排查内存泄露,查看堆中(仅存活的)各 class 的实例数、总占用空间
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

5.3 jstack

jstack 1162 > jstack.log ## 可生成应用的各线程 StackTrace
  • 1

5.4 jcmd

jcmd ## 类似于 jps,查看 java 进程
jcmd 1162 help ## 查看该进程支持的命令

jcmd 1162 VM.uptime ## 显示启动时间
jcmd 1162 VM.flags ## 显示VM标志
jcmd 1162 VM.version ## 查看虚拟机版本
jcmd 1162 VM.command_line ## 显示命令行及参数
jcmd 1162 VM.system_properties ## 显示系统属性

jcmd 1162 GC.run ## 执行 System.gc()
jcmd 1162 GC.run_finalization ## 执行 System.runFinalization()
jcmd 1162 GC.class_histogram ## 相当于 jmap -histo:live 1162
jcmd 1162 GC.heap_dump tomcat.hprof ## 生成堆快照文件
jcmd 1162 Thread.print ## 相当于 jstack 1162
jcmd 1162 PerfCounter.print ## 显示进程内各种计数器
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

6 开发监控系统

假设有个需求(这里只是为了演示,现实中不会这么简单粗暴,现实中还需要限制在凌晨才触发):Heap 使用率高于 60%,就要求强制 FullGC。

6.1 Shell 脚本

PID=`jps | grep Bootstrap | awk '{print $1}'`

## 计算 Heap 使用率
## 下面命令会输出 Eden/S0/S1/Tenured 各自的总空间和已用空间,很容易算出 Heap 使用率: 
## used(Eden+S0+S1+Tenured)/total(Eden+S0+S1+Tenured)
# jstat -gc $PID

## 判断使用率大于 60% 才执行 FullGC
jcmd $PID GC.run
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

6.2 Java 代码

代码中使用的“java.lang:type=Memory”、“HeapMemoryUsage”可以借助 VisualVM/MBeans插件的 Attribtes/Operations 标签页中找到,如下图: 
JVM 优化实战[通俗易懂]

package wang.kefeng.JmxAdmin;

import java.lang.management.MemoryUsage;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** * @author http://kefeng.wang * @date 2016-11-24 20:20:08 */
public class App { 
     
    private static final String JMX_HOSTNAME = "192.168.214.128:1090";
    private static final String JMX_USERNAME = "jmxadmin";
    private static final String JMX_PASSWORD = "jmxpwd";

    private static final Logger logger = LoggerFactory.getLogger(App.class);

    public static void main(String[] args) throws Exception {
        // 1.建立连接(mbsc)
        String jmxURL = "service:jmx:rmi:///jndi/rmi://" + JMX_HOSTNAME + "/jmxrmi";
        JMXServiceURL serviceURL = new JMXServiceURL(jmxURL);

        Map<String, Object> map = new LinkedHashMap<>();
        map.put("jmx.remote.credentials", new String[] { JMX_USERNAME, JMX_PASSWORD });
        JMXConnector connector = JMXConnectorFactory.connect(serviceURL, map);
        MBeanServerConnection mbsc = connector.getMBeanServerConnection();

        // 2.获取远程应用数据
        ObjectName objectName = new ObjectName("java.lang:type=Memory");
        Object heapMemoryUsage = mbsc.getAttribute(objectName, "HeapMemoryUsage");
        MemoryUsage usage = MemoryUsage.from((CompositeDataSupport) heapMemoryUsage);

        // 示例:如果 Heap 使用率大于 60%,则请求 FullGC
        long usedRate = usage.getUsed() * 100 / usage.getMax();
        logger.info("usedRate={}, {} / {}", usedRate, usage.getUsed(), usage.getMax());
        if (usedRate > 30) {
            mbsc.invoke(objectName, "gc", null, null);
            logger.info("gc() OK.");
        }

        // 3.更多有用的 MBeans
        // (1)com.sun.management:type=HotSpotDiagnostic
        // dumpHeap(), getVMOption(), setVMOption()
        // (2)java.util.logging:type=Logging
        // getLoggerLevel(), setLoggerLevel()
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

7 内存泄露插件

7.1 内存泄露现象

老年代越来越大,GC越来越频繁、执行时间越来越长,而且GC后内存未释放。

7.2 生成快照文件(hprof Heap信息文件)

  • 使用Java的jmap命令来生成;
  • 通过JMX的MBean用Java代码生成;

7.3 分析dump文件

  • 最佳方案是使用 Eclipse MAT 插件;
  • 其他候选方案:Java 自带工具 Visual VM / jhat、IBM HeapAnalyzer;

7.4 分析内存泄漏

可看到可疑的内存泄露对象,看到占用空间大的对象及其调用关系。

8 GC日志

8.1 开启gc日志文件

### Linux: $CATALINA_HOME/bin/startup.sh
export JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDateStamps -XX:+PrintGCDetails
   -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -Xloggc:$CATALINA_BASE/logs/gc.log"
  • 1
  • 2
  • 3

8.2 日志文件格式解析

[停顿类型 
  [新生代: GC前本区域已用容量 -> GC后本区域已用容量 (本区域总容量), 本区域GC耗时] 
  [老年代: GC前本区域已用容量 -> GC后本区域已用容量 (本区域总容量), 本区域GC耗时] 
    GC前Heap已用容量 -> GC后Heap已用容量 (Heap总容量) 
  [永久代: GC前本区域已用容量 -> GC后本区域已用容量 (本区域总容量), 本区域GC耗时] 
  [Times: 用户耗时=xx 系统耗时=yy, 实际耗时=zz secs]

==== server 模式的 GC+FullGC ==== 
新生代:PSYoungGen=Parallel Scavenge 
老年代:ParOldGen=Parallel Old 
永久代:PSPermGen

[GC
    [PSYoungGen: 6980K->600K(9216K)]
        6980K->6744K(19456K), 0.0028901 secs]
    [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC
    [PSYoungGen: 600K->0K(9216K)]
    [ParOldGen: 6144K->6617K(10240K)]
        6744K->6617K(19456K)
    [PSPermGen: 2567K->2566K(21504K)], 0.0095238 secs]
    [Times: user=0.02 sys=0.00, real=0.02 secs]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

==== client 模式的 GC+FullGC ==== 
新生代:DefNew=Serial(Default New Generation) 
老年代:Tenured 
永久代:Perm

[GC
    [DefNew: 6871K->382K(9216K), 0.0037941 secs]
    [Tenured: 6144K->6525K(10240K), 0.0033262 secs]
        6871K->6525K(19456K),
    [Perm : 186K->186K(12288K)], 0.0081090 secs]
    [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC
    [Tenured: 6525K->6514K(10240K), 0.0026225 secs]
        6525K->6514K(19456K),
    [Perm : 186K->186K(12288K)], 0.0028221 secs]
    [Times: user=0.00 sys=0.00, real=0.00 secs]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

=================================

8.3 gc.log 解析工具

8.3.1 在线分析

http://gceasy.io/

8.3.2 ga456(IBM)

https://www.ibm.com/developerworks/community/alphaworks/tech/pmat 
ftp://public.dhe.ibm.com/software/websphere/appserv/support/tools/pmat/ga456.jar

8.3.3 HPjmeter

https://h20392.www2.hpe.com/portal/swdepot/displayProductInfo.do?productNumber=HPJMETERSW 
需要注册帐号并登录,最终下载页中选择“Use Standard Download”,Windows上可下载这两个: 
MS Windows XP/Vista/7 HPjmeter 4.4.00.00 Console – Oct 2014 (Z7550-01611_hpjmeter_console_4.4.00.00_windows_setup.exe) 
HPjmeter 4.4.00.00 Console jar file zip format – Feb 2015 (Z7550-63266_hpjmeter_4.4.00.00.zip)

8.3.4 GCViewer

http://www.tagtraum.com/gcviewer.html 
http://www.tagtraum.com/gcviewer-download.html 
http://www.tagtraum.com/download/gcviewer-1.29-bin.zip

8.3.5 IBM GCMV(Eclipse 插件)

GCMV=Garbage Collection and Memory Visualizer 
插件中心搜索 “GCMV” 来安装,然后在菜单中打开: Window / Perspective / Open Perspective / GCMV

8.3.6 gchisto(VisualVM 插件)

https://gchisto.dev.java.net/ 
http://java.net/projects/gchisto 
http://pietrowski.info/wp-content/uploads/2009/06/GCHisto.tgz

8.3.7 其他更多

https://code.google.com/archive/p/gclogviewer/ 
https://code.google.com/archive/p/verbosegcanalyzer 
http://fasterj.com/tools/gcloganalysers.shtml 
http://techblog.netflix.com/2013/05/garbage-collection-visualization.html

版权声明:【自由转载-非商用-非衍生-保持署名】-转载请标明作者和出处。 https://blog.csdn.net/kefengwang/article/details/54378235
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/133294.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • WebPack_钢铁雄心4toolpack

    WebPack_钢铁雄心4toolpack关于Devtool该选项控制是否以及如何生成源映射。官网上给出的可选值有:其中一些值适合开发,一些用于生产。对于开发,您通常需要快速的SourceMaps,以bundle的大小为代价,但是对于生产,您需要独立的SourceMaps,这是精确的,并且支持最小化。选择一种源映射样式,以增强调试过程。这些值可以显著地影响构建和重建速度。而不是使用devtool选项还可以使用Sourc…

  • Pikachu-XXE「建议收藏」

    Pikachu-XXE「建议收藏」0x00XXE-“xmlexternalentityinjection”既”xml外部实体注入漏洞”。概括一下就是”攻击者通过向服务器注入指定的xml实体内容,从而让服务器按照指定的配置进行执行,导致问题”也就是说服务端接收和解析了来自用户端的xml数据,而又没有做严格的安全控制,从而导致xml外部实体注入。现在很多语言里面对应的解析xml的函数默认是禁止解析外部实体内容的,从…

  • rider 激活码【2021.10最新】

    (rider 激活码)最近有小伙伴私信我,问我这边有没有免费的intellijIdea的激活码,然后我将全栈君台教程分享给他了。激活成功之后他一直表示感谢,哈哈~https://javaforall.cn/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~23LN…

  • 判断同构数 c语言程序(java人脸识别算法)

    给定的两个邻接矩阵,判断其三个必要非充分条件:①结点数目相同②变数相同③度数相同的结点数相同以①②③为前提进行矩阵变换,看给定的两个矩阵中,其中的一个矩阵是否能变换为另一个矩阵;实现代码和说明:#include<iostream>#include<stdlib.h>#defineMAX100usingnamespacestd;structAdjacencyMatrix{//邻接矩阵intpoints;/

  • vuejs生命周期函数(什么是vue的生命周期)

    用Vue框架,熟悉它的生命周期可以让开发更好的进行。首先先看看官网的图,详细的给出了vue的生命周期:它可以总共分为8个阶段:beforeCreate(创建前),created(创建后),beforeMount(载入前),mounted(载入后),beforeUpdate(更新前),updated(更新后),beforeDestroy(销毁前),de

  • 把ocx打包成CAB,并签名

    把ocx打包成CAB,并签名准备好工具包,微软的IESDK里包含这些工具, 但是那个开发包太过庞大,而且操作起来也稍微得繁琐了一些你只需要下载这么几个文件就可以了 文中提到的数字签名工具包,请在此处下载&#

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号