在一个JVM进程中会存在有多个对象实例,如果要想获取所有对象的信息,就可以通过JDK提供的jmap工具完成,另外使用该工具还可以直接获取到指定进程的堆内存使用信息,开发者可以通过jmap --help 命令查看该命令相关的参数。

1、查看JVM进程中的对象信息
导致JVM性能问题的核心一点在于对象过多,每一个对象又无法进行有效的释放的,所以产生了JVM里面的Full GC。
在IDEA中直接运行下述代码:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class YootkJVM {
public static String base = "yootk.com" ; //定义一个基础字符串
public static void main(String[] args) throws Exception {
List<String> all = new ArrayList<>();
for (int x = 0; x< Integer.MAX_VALUE; x++) {
TimeUnit.SECONDS.sleep(5); //休眠5秒
String str = base + base;
base = str;
all.add(str);
}
}
}
然后在控制台中执行 jps 命令,查询出当前正在执行的进程:

根据上述查询到的进程ID(即13544),使用下述命令获取该进程中的对象信息,如下图所示:
jmap -histo 进程ID

以上所返回的对象信息,有很多是在JVM运行的时候自己追加的一些程序类,这些内容在命令行的状态下感觉非常的多。
假如我现在是一个运维,即便知道有很多的对象信息,也无法进行分析,应该将这些数据转交给开发人员,可以考虑将当前的对象的数据信息保存在一个名为“a.log”的文件之中。因此我们可以使用下述命令将该进程中所有存活的对象的数据信息保存在指定文件中:
jmap -histo:live 进程ID > 文件名称

执行完上述命令后CMD中不会有任何的输出,这个时候直接到D盘目录下可以看到生成了名为“a.log”的文件, 并且文件里面的内容和前面直接在CMD中打印出来的信息完全一样。
2、获取堆内存信息
获取某一个进程的JVM堆内存信息,可以使用下述命令:
jmap -heap 进程ID

通过该命令可以看到Java堆和永久代的详细信息、空间使用率、当前用的是哪种收集器等。
3、获取堆内存信息并保存在指定文件中
获取某一个进程的JVM堆内存信息并保存在指定文件中,可以使用下述命令:
jmap -dump:live,format=b,file=test-help.data 进程ID

执行完该命令后在D盘目录下就会多了一个名为 “test-help.data”的文件,直接打开该文件可以看到里面的内容都是二进制数据,这个是不能直接进行查看的,但是可以通过其它的工具来查看这个文件。
jmap的工具是在JDK一直提供的一个监控工具,但是在JDK9之后为了更加规范化的去运行应用程序,提供了一个新的子命令:jhsdb,可以直接通过这个命令触发之前的jstat、jmap、jstack命令。
例如查看堆内存信息:
jhsdb jmap --heap --pid 进程ID
4、实战操作
问题:查看一个新项目JVM内存分配情况以及使用率,便于为出现的bug进行问题定位提供参考,此时你应该怎么做?
解决方法:第一步使用jps查看我们应用的进程号

第二步:通过 jmap -heap pid 命令查看堆内存分配情况和使用率
从 Parallel cC with 8 thread(s) 这行输出可以看出当前使用的是并行垃圾收集器。
以下为各个配置参数的详细介绍:
MaxHeapSize:总共分配了2006MB内存给堆
NewSize:新生代堆空间的默认值
MaxNewSize:新生代最大堆空间值
OldSize:老年代堆空间的默认值
NewRatio:新生代和老年代的堆空间比值,即新生代:老年代 = 1:2
SurvivorRatio:两个Survivor区和Eden区的堆空间比值为8,即 S0:S1:Eden = 1:1:8
capacity:当前总共分配的内存
used:已使用的内存
free:空虚内存
本文介绍了如何利用jmap工具监控JVM进程,包括查看对象信息、获取堆内存信息并保存到文件。通过jmap命令,可以检查JVM的内存分配情况,为故障排查提供帮助。
447

被折叠的 条评论
为什么被折叠?



