一、 命令方法总结:
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
参考资料
链接: https://www.jianshu.com/p/15597b3d2da8.
链接: https://blog.csdn.net/u013068789/article/details/104827311/.
链接: https://www.cnblogs.com/kongzhongqijing/articles/3621163.html.
(1)
jmap
jdk安装后会自带一些小工具,jmap命令(Java Memory Map)是其中之一。主要用于打印指定Java进程(或核心文件、远程调试服务器)的共享对象内存映射或堆内存细节。
jmap命令可以获得运行中的jvm的堆的快照,从而可以离线分析堆,以检查内存泄漏,检查一些严重影响性能的大对象的创建,检查系统中什么对象最多,各种对象所占内存的大小等等。可以使用jmap生成Heap Dump。
jmap 使用总结: jmap [ option ] pid (to connect to remote debug server)
例如: jmap -histo:live 18476
options: 说明
(1.1)-dump:[live,]format=b,file= 使用hprof二进制形式,输出jvm的heap内容到文件, live子选项是可选的,假如指定live选项,那么只输出活的对象到文件.
(1.2)-histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量.
示例:
jmap -histo pid 展示class的内存情况
说明:instances(实例数)、bytes(大小)、classs name(类名)。它基本是按照使用使用大小逆序排列的。
#instance 是对象的实例个数
#bytes 是总占用的字节数
class name 对应的就是 Class 文件里的 class 的标识
B 代表 byte
C 代表 char
D 代表 double
F 代表 float
I 代表 int
J 代表 long
Z 代表 boolean
前边有 [ 代表数组, [I 就相当于 int[]
对象用 [L+ 类名表示
从打印结果可看出,类名中存在[C、[B等内容,
只知道它占用了那么大的内存,但不知道由什么对象创建的。下一步需要将其他dump出来,使用内存分析工具进一步明确它是由谁引用的、由什么对象。
(2)
jstat命令格式为:
利用“虚拟机统计信息监视工具:jstat”监视虚拟机各种运行状态信息。
jstat [ option vmid [interval[s|ms] [count]] ]
使用命令如下:
jstat -gcutil 18476 1000
意思是每1000毫秒查询一次,一直查。gcutil的意思是已使用空间站总空间的百分比。
查询结果表明:这台服务器的新生代Eden区(E,表示Eden)使用了28.30%(最后)的空间,两个Survivor区(S0、S1,表示Survivor0、Survivor1)分别是0和8.93%,老年代(O,表示Old)使用了87.33%。程序运行以来共发生Minor GC(YGC,表示Young GC)101次,总耗时1.961秒,发生Full GC(FGC,表示Full GC)7次,Full GC总耗时3.022秒,总的耗时(GCT,表示GC Time)为4.983秒。
正常的
不正常的
(3)
jps 命令
jps是JVM进程查找工具,类似于linux的ps命令
(1.1)
jps cmd 中 一般只用它查看Java进程id **
(1.2)jps 没有启动任何Java项目时 没有Java进程
jps //仅显示进程id,主类名
C:\Users\wyy>jps
16544 Jps
9412
19512 Launcher
24040 Launcher
(1.3)jps -l 没有启动任何Java项目时 没有Java进程
jps -l //输出完全的包名,主类名,jar完全路径名
C:\Users\wyy>jps -l
6240 jdk.jcmd/sun.tools.jps.Jps
9412
19512 org.jetbrains.jps.cmdline.Launcher
24040 org.jetbrains.jps.cmdline.Launcher
(1.4)启动一个 Java springboot项目 一个 Java tomcat web项目
Java进程为 5376 、676
C:\Users\wyy>jps -l
5376 com.oujiong.websocket.Application
20548 org.jetbrains.jps.cmdline.Launcher
676 org.apache.catalina.startup.Bootstrap
9412
22552 jdk.jcmd/sun.tools.jps.Jps
15436 org.jetbrains.jps.cmdline.Launcher
其他命令:
jps [ options ] [ hostid ]
选项
-V 输出通过flag文件传递到JVM中的参数(.hotspotrc文件或-XX:Flags=所指定的文件
-Joption 传递参数到vm,例如:-J-Xms48m
缺点:jps有个缺点是只能显示当前用户的进程id,要显示其他用户的还只能用linux的ps命令。
命令不能使用原因:Linux三个命令都能用 windows好像就能用 jps这个命令
java程序启动后,会在目录/tmp/hsperfdata_{userName}/下生成几个文件,文件名就是java进程的pid,因此jps列出进程id就是把这个目录下的文件名列一下而已,至于系统参数,则是读取文件中的内容。
我们来思考下:如果由于磁盘满了,无法创建这些文件,或者用户对这些文件没有读的权限。又或者因为某种原因这些文件或者目录被清除,出现以上这些情况,就会导致jps命令失效。
如果jps命令失效,而我们又要获取pid,还可以使用以下两种方法:
top | grep java
ps -ef |grep java
(4)
jinfo命令 主要查看Java进程 的jvm内存大小信息
(1.1)使用方式介绍:
Usage:
jinfo
(to connect to a running process)
where is one of:
-flag to print the value of the named VM flag
-flag [+|-] to enable or disable the named VM flag
-flag = to set the named VM flag to the given value
-flags to print VM flags
-sysprops to print Java system properties
to print both VM flags and system properties
-? | -h | --help | -help to print this help message
(1.2)
jinfo 5376
可以查看这个Java进程的很多信息包括jvm内存大小、项目所在路径等等
例如: -XX:MarkStackSize=4194304 -XX:MaxHeapSize=4125 097 984 -XX:MaxNewSize=2 474 639 360
(1.3)
jinfo -flag MaxNewSize 21236
-XX:MaxNewSize=2474639360
jinfo -flag MaxHeapSize 21236
-XX:MaxHeapSize=4125097984
jinfo -flag MaxHeapSize 10284
-XX:MaxHeapSize=4125097984
(5)
修改java启动参数_如何修改jvm启动参数 方式
用java命令查看。
第一种 一般用于生产环境 :用java -option进行修改参数。
执行启动设置Jvm参数的操作。
java -jar -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -Xms1024m -Xmx1024m -Xmn256m -Xss256k -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC myApp-1.0.0.jar
第二种 一般用于测试环境 :还有tomcat,eclipse启动时通过配置文件加载的。
(11) JVM参数整理
-Xms 初始堆内存大小,默认物理内存64/1
-Xms = -XX:InitialHeapSize
-Xmx 最大堆内存,默认物理内存4/1
-Xmx = -XX:MaxHeapSize
-Xss 栈内存大小
设置单个线程栈大小,一般默认512~1024kb。
单个线程栈大小跟操作系统和JDK版本都有关系
-Xss = -XX:ThreadStackSize
-Xmn 年轻代大小
-XX:MetaspaceSize 元空间大小
元空间本质跟永久代类似,都是对JVM规范中方法区的实现。
不过元空间与永久代最大的区别在于:元空间并不在虚拟机中,而是使用本机内存。
因此,元空间大小仅受本地内存限制。
-XX:+PrintGCDetails 打印GC详细日志信息
-XX:SurvivorRatio 幸存者比例设置
-XX:NewRatio 新生代比例设置
-XX:MaxTenuringThreshold 进入老年代阈值设置
-XX:MaxNewSize 年轻代最大值(for 1.3/1.4)
(6)
java -jar 命令 在生产环境部署时可以用到
这里 变更的参数只是针对 当前 启动的Java jvm进程生效
例如:
java -jar -Xms50m -Xmx50m -Xmn50m -Xss500k spring-study-0.0.1-SNAPSHOT.jar
(7)
一个Java内存泄漏的排查案例
某个业务系统在一段时间突然变慢,我们怀疑是因为出现内存泄露问题导致的,于是踏上排查之路。
2.1 确定频繁Full GC现象
首先通过“虚拟机进程状况工具:jps”找出正在运行的虚拟机进程,最主要是找出这个进程在本地虚拟机的唯一ID
使用jps:jps -l
使用ps:ps aux | grep tomat
找到你需要监控的ID(假设为20954),再利用“虚拟机统计信息监视工具:jstat”监视虚拟机各种运行状态信息。
jstat命令格式为:
jstat [ option vmid [interval[s|ms] [count]] ]
使用命令如下:
jstat -gcutil 20954 1000
意思是每1000毫秒查询一次,一直查。gcutil的意思是已使用空间站总空间的百分比。
2.2 找出导致频繁Full GC的原因
分析方法通常有两种:
1)把堆dump下来再用MAT等工具进行分析,但dump堆要花较长的时间,并且文件巨大,再从服务器上拖回本地导入工具,这个过程有些折腾,不到万不得已最好别这么干。
2)更轻量级的在线分析,使用“Java内存影像工具:jmap”生成堆转储快照(一般称为headdump或dump文件)。
jmap命令格式:
jmap [ option ] vmid
使用命令如下:
jmap -histo:live 20954
查看存活的对象情况
2.3 如果上面一步还无法定位到关键信息,那么需要拿到heap dump,生成离线文件,做进一步分析,命令:
[html] view plain copy
jmap -dump:live,format=b,file=heap.hprof 3514
2.4 拿到heap dump文件,利用eclipse插件MAT来分析heap profile。
a. 安装MAT插件
b. 在eclipse里切换到Memory Analysis视图
c. 用MAT打开heap profile文件。
(8)
获得jvm 内存参数代码示例
MonitorService service = new MonitorService();
MonitorInfo monitorInfo = service.getMonitorInfoBean();
System.out.println("JVM可使用内存=" + monitorInfo.getTotalMemory() +
"MB");
System.out.println("JVM剩余内存=" + monitorInfo.getFreeMemory() + "MB");
System.out.println("JVM最大可使用内存=" + monitorInfo.getMaxMemory() +
"MB");
System.out.println("操作系统=" + monitorInfo.getOsName());
System.out.println("核心数=" + monitorInfo.getProcessors());
System.out.println("总的物理内存=" + monitorInfo.getTotalMemorySize() + "GB");
System.out.println("剩余的物理内存=" + monitorInfo.getFreeMemorySize() + "GB");
System.out.println("已使用的物理内存=" + monitorInfo.getUsedMemorySize() + "GB");
System.out.println("cpu占有率=" + monitorInfo.getCpuRatio() + "kb");
System.out.println("线程总数=" + monitorInfo.getTotalThread() + "条");
System.out.println("ProcessCpuLoad cpu占有率=" + monitorInfo.getProcessCpuLoad() + "kb");
System.out.println("systemCpuLoad cpu占有率=" + monitorInfo.getSystemCpuLoad() + "条");
public class MonitorService {
public MonitorInfo getMonitorInfoBean() {
double mb = 1024 * 1024 * 1.0;
double gb = 1024 * 1024 * 1024 * 1.0;
// jvm
double totalMemory = Runtime.getRuntime().totalMemory() / mb;
double freeMemory = Runtime.getRuntime().freeMemory() / mb;
double maxMemory = Runtime.getRuntime().maxMemory() / mb;
// os
OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory
.getOperatingSystemMXBean();
String osName = System.getProperty("os.name");
double totalMemorySize = osmxb.getTotalPhysicalMemorySize() / gb;
double freeMemorySize = osmxb.getFreePhysicalMemorySize() / gb;
double usedMemorySize = (osmxb.getTotalPhysicalMemorySize() - osmxb
.getFreePhysicalMemorySize()) / gb;
double processCpuLoad = (osmxb.getProcessCpuLoad()) / gb;
double systemCpuLoad = osmxb.getSystemCpuLoad() / gb;
// 获得线程总数
ThreadGroup parentThread;
for (parentThread = Thread.currentThread().getThreadGroup(); parentThread
.getParent() != null; parentThread = parentThread.getParent())
;
int totalThread = parentThread.activeCount();
// MonitorInfo
MonitorInfo infoBean = new MonitorInfo();
infoBean.setTotalMemory(getIntValue(totalMemory));
infoBean.setFreeMemory(getIntValue(freeMemory));
infoBean.setMaxMemory(getIntValue(maxMemory));
infoBean.setOsName(osName);
infoBean.setTotalMemorySize(getIntValue(totalMemorySize));
infoBean.setFreeMemorySize(getIntValue(freeMemorySize));
infoBean.setUsedMemorySize(getIntValue(usedMemorySize));
infoBean.setProcessors(Runtime.getRuntime().availableProcessors());
infoBean.setProcessCpuLoad(getIntValue(processCpuLoad)) ;
infoBean.setSystemCpuLoad(getIntValue(systemCpuLoad));
infoBean.setTotalThread(totalThread);
return infoBean;
}
/**
* 四舍五入取整
*/
private static int getIntValue(double d) {
return new BigDecimal(d).setScale(0, BigDecimal.ROUND_HALF_UP)
.intValue();
}
}
public class MonitorInfo {
/** jvm可使用内存. */
private long totalMemory;
/** jvm剩余内存. */
private long freeMemory;
/** jvm最大可使用内存. */
private long maxMemory;
/** 操作系统. */
private String osName;
/** 总的物理内存. */
private long totalMemorySize;
/** 剩余的物理内存. */
private long freeMemorySize;
/** 已使用的物理内存. */
private long usedMemorySize;
/** 核心数. */
private int processors;
/** 线程总数. */
private int totalThread;
/** cpu使用率. */
private double cpuRatio;
private double processCpuLoad ;
private double systemCpuLoad;
}
(9)
拿到heap dump,生成离线文件
jmap -dump:live,format=b,file=heap.hprof 3514
例如:
C:\Users\wyy>jmap -dump:live,format=b,file=heap.hprof 18476
Heap dump file created
(10)
拿到heap dump文件,利用eclipse插件MAT来分析heap profile。
a. 安装MAT插件
b. 在eclipse里切换到Memory Analysis视图
c. 用MAT打开heap profile文件。
Idea 安装
内存分析工具之独立版MAT使用
当运行java程序发生OOM时,可以通过内存分析工具MAT进行问题跟踪,并解决
MAT是eclipse的插件,针对idea,在本机安装独立版使用
测试 示例总结:
1、
链接: https://www.cnblogs.com/lshan/p/12932605.html.
测试用命令行 修改 jar包中的 jvm参数 适用于线上环境
先查看 jar包运行时 jvm参数,然后 命令行修改jar 包jvm参数,然后再启动 看jvm参数是否生生效
(1)启动 springboot项目jar包运行
cmd 中 进入到jar包目录
java -jar name 如:java -jar spring-boot-websocket-study-0.0.1-SNAPSHOT.jar
(2)查看启动 jar进程
C:\Users\wyy>jps -l
15008 org.jetbrains.jps.cmdline.Launcher
21616 org.jetbrains.jps.cmdline.Launcher
28340 jdk.jcmd/sun.tools.jps.Jps
26984 spring-boot-websocket-study-0.0.1-SNAPSHOT.jar
(3)查看进程jvm现有参数
原始值
C:\Users\wyy>jinfo -flag MaxHeapSize 26984
-XX:MaxHeapSize=4125097984
(4)先停掉现有jar 包进程
(5)cmd 命令修改 jar包 jvm参数
在 cmd中
java -jar -Xmx1024m spring-boot-websocket-study-0.0.1-SNAPSHOT.jar
项目会启动
(6)查看 Java进程 jps -l
7920 spring-boot-websocket-study-0.0.1-SNAPSHOT.jar
(7)
C:\Users\wyy>jinfo -flag MaxHeapSize 7920
-XX:MaxHeapSize=1073741824 (除以两次1024 就是BM的值了)
(8)
参数已经变了 但是这个只是针对这一个Java项目进程 而言的更改 只对这个jvm虚拟机生效
(9)
另一的Java进程的这个参数还是不会变的 已经验证
C:\Users\wyy>jinfo -flag MaxHeapSize 17860
-XX:MaxHeapSize=4125097984
(10)其他参数也可以修改
java -jar -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -Xms1024m -Xmx1024m -Xmn256m -Xss256k -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC myApp-1.0.0.jar
2、
模拟泄漏 查找问题
(1)记录一次生产环境下的jvm内存泄露问题和分析解决过程
链接: https://blog.csdn.net/wk52525/article/details/84566560
.
链接: https://blog.csdn.net/fishinhouse/article/details/80781673?utm_medium=distribute.pc_relevant_download.none-task-blog-2defaultBlogCommendFromBaidudefault-13.test_version_3&depth_1-utm_source=distribute.pc_relevant_download.none-task-blog-2defaultBlogCommendFromBaidudefault-13.test_version_
.
(2)制造 内存泄漏的例子 调小jvm参数 启动项目
java -jar -Xms50m -Xmx50m -Xmn50m -Xss500k spring-boot-websocket-study-0.0.1-SNAPSHOT.jar
内存泄漏的例子
如果长生命周期的对象持有短生命周期的引用,就很可能会出现内存泄露
比如下面的代码,这里的object实例,其实我们期望它只作用于method1()方法中,且其他地方不会再用到它,但是,当method1()方法执行完成后,object对象所分配的内存不会马上被认为是可以被释放的对象,只有在Simple类创建的对象被释放后才会被释放,严格的说,这就是一种内存泄露。
自己写个死循环
public class SimpleWyy {
Object object;
public void method1(){
object = new Object();
System.out.println("======");
//...其他代码
// object = null;
}
}
public static void main(String[] args){
while (1==1){
List list = new ArrayList<>();
list.add("11");
list.add("22");
SimpleWyy simpleWyy = new SimpleWyy();
simpleWyy.method1();
}
}
(3) 查看进程号
jps -l
18476 spring-boot-websocket-study-0.0.1-SNAPSHOT.jar
(4)
利用“虚拟机统计信息监视工具:jstat”监视虚拟机各种运行状态信息。
jstat命令格式为:
jstat [ option vmid [interval[s|ms] [count]] ]
使用命令如下:
jstat -gcutil 18476 1000
意思是每1000毫秒查询一次,一直查。gcutil的意思是已使用空间站总空间的百分比。
(5)
使用 jmap
-dump:[live,]format=b,file= 使用hprof二进制形式,输出jvm的heap内容到文件, live子选项是可选的,假如指定live选项,那么只输出活的对象到文件.
-histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量.
找出导致频繁Full GC的原因
C:\Users\wyy>jmap -histo:live 18476
num #instances #bytes class name (module)
1: 56780 4235424 [B (java.base@11.0.9)
2: 1162 2739000 [C (java.base@11.0.9)
3: 51799 1243176 java.lang.String (java.base@11.0.9)
4: 8407 1002312 java.lang.Class (java.base@11.0.9)
(6)
那么需要拿到heap dump,生成离线文件,做进一步分析
[html] view plain copy
jmap -dump:live,format=b,file=heap.hprof 3514
C:\Users\wyy>jmap -dump:live,format=b,file=heap.hprof 18476
Heap dump file created
(7) 拿到heap dump文件,利用eclipse插件MAT来分析heap profile。
a. 安装MAT插件
b. 在eclipse里切换到Memory Analysis视图
c. 用MAT打开heap profile文件。
mat 下载
https://www.eclipse.org/mat/downloads.php
mat安装和使用
https://blog.csdn.net/haoshaoxing/article/details/82761718?utm_term=idea%E7%9A%84mat&utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allsobaiduweb~default-3-82761718&spm=3001.4430
mat 使用和介绍
https://blog.csdn.net/weixin_39777637/article/details/110844668?utm_medium=distribute.pc_relevant_download.none-task-blog-baidujs-1.nonecase&depth_1-utm_source=distribute.pc_relevant_download.none-task-blog-baidujs-1.nonecase
Dominator Tree
MAT根据堆上的对象引用关系构建了支配树(Dominator Tree)
Shallow vs. Retained Heap
Shallow heap是一个对象本身占用的堆内存大小。一个对象中,每个引用占用8或64位,Integer占用4字节,Long占用8字节等等。
Retained heap,对象X的Retained heap指的时候它的Retained set中的所有对象的Shallow si的和,换句话说,Retained heap指的是对象X的保留内存大小,即由于它的存活导致多大的内存也没有被回收。
(8) 参考资料
https://blog.csdn.net/fishinhouse/article/details/80781673?utm_medium=distribute.pc_relevant_download.none-task-blog-2defaultBlogCommendFromBaidudefault-13.test_version_3&depth_1-utm_source=distribute.pc_relevant_download.none-task-blog-2defaultBlogCommendFromBaidudefault-13.test_version_
https://blog.csdn.net/u013068789/article/details/104827311/
jmap名称:Java Memory Map(内存映射)
官方文档:https://docs.oracle.com/javase/1.5.0/docs/tooldocs/share/jmap.html
java命令–jmap命令使用(这篇文章写得非常好)
https://www.cnblogs.com/kongzhongqijing/articles/3621163.html
Java虚拟机的内存组成以及堆内存介绍
http://www.hollischuang.com/archives/80
Java GC工作原理
http://www.hollischuang.com/archives/76
JVM内存区域划分Eden Space、Survivor Space、Tenured Gen,Perm Gen解释
https://www.cnblogs.com/kxm87/p/7205414.html
JDK,JRE,JVM区别与联系
http://www.hollischuang.com/archives/78
【JVM】12_空间分配担保(没看懂?)
https://blog.csdn.net/u013295276/article/details/78468790?locationNum=1&fps=1
https://blog.csdn.net/weixin_39922476/article/details/111252622?utm_term=idea%E7%9A%84mat&utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allsobaiduweb~default-0-111252622&spm=3001.4430
(9)
使用分析软件 你要思考
什么情况下会FULLGC 、什么时候对象会过大 一直创建对象但是不释放 对象过多和对象过大区别、
一直创建对象但是对象一直不回收 会出现什么情况 等等 多练习就会很熟练了