如何生成 JVM 堆内存转储?
Java堆转储是在某个时间点存在于 JVM( Java虚拟机)中的所有Java对象的快照。 JVM 为堆内存中的类实例或数组的对象分配内存。当不再需要或不再引用这些对象时,垃圾收集器会运行并回收这些对象占用的内存空间。
堆转储采用二进制格式,扩展名为 .hprof 。可以使用 JVisualVM 和 Eclipse MAT(内存分析器工具)等应用程序打开和分析它。我们生成Java内存堆转储来识别内存泄漏等问题并优化应用程序中的内存使用。
方法:
有生成Java内存堆转储的不同方式。 JDK 提供了各种用于生成堆转储的工具。这些工具位于JDK主目录下的bin文件夹中。让我们讨论如何生成JVM Heap Dump,如下所示:
- 使用 jmap 命令
- 在终端上使用 jcmd 命令
- 使用 JVisualVM 工具
- 识别 HeapDumpOnOutOfMemory
- 使用 JMX 控制台
- 通过编写程序使用 HotSpotDiagnosticMBean
方法一:使用map命令
jmap 是在 JDK 主目录的 bin 文件夹中运行的命令。它提供有关内存使用情况的统计信息。结构如下:
例子
jmap -dump:[live],format=b,file=
live:- This parameter is optional. If set, it prints all those objects that
have active references.
format = b , which means the heap dump file is in binary format. It is not necessary
to set this parameter.
file = indicates where the heap dump file will be generated.
:- process id of the java process
现在,为了获取正在运行的Java进程的进程 ID,可以使用以下定义的选项之一:
1.1
jps
我们从安装了 JDK 的 Unix 终端或 Windows 命令提示符键入此命令。它给出了正在运行的Java进程的进程 ID
1.2
ps -eaf| grep java
这给出了所有正在运行的Java进程的进程 ID。它仅适用于 Unix 终端
1.3在 windows 操作系统中使用任务管理器应用程序。
方法二:在终端上使用 jcmd 命令
此命令发送 一种 请求 JVM 生成堆转储。它的参数之一是 GC.heap_dump。如下图所示:
jcmd GC.heap_dump
- Process id of java process
- Path where the heap dump is to be generated
方法三:使用JVisualVM工具
这是一个打包在 JDK 中的工具。它有助于监视和排除Java应用程序的故障。它具有简单直观的图形用户界面。我们在开始菜单中输入jvisualvm ,或者在Unix下通过命令提示符或终端窗口进入JDK主目录的bin目录,输入jvisualvm
它启动一个Java Visual VM 应用程序。左侧显示当前运行的Java进程。右键单击要生成其堆转储的进程 ID。当我们点击 heap dump 时,它会为选定的进程生成 heap dump。在基本信息下,它显示生成堆转储的文件路径。
方法 4:识别 HeapDumpOnOutOfMemory
当应用程序遇到Java.lang.OutOfMemoryError 时,捕获堆转储是理想的选择。堆转储有助于识别内存中的活动对象及其占用的内存百分比。
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=
在设置此系统属性的情况下运行Java应用程序时,JVM 会在遇到 OutOfMemoryError 时获取堆转储的快照。
方法五: 使用 JMX 控制台
有一个具有堆转储操作的热点诊断 MBean。我们使用jmx客户端(如jconsole)来调用MBean操作。通过 JConsole,我们可以通过指定主机和端口号以及用户名/密码来连接到本地Java进程或远程进程。一旦我们连接到进程 ID,jconsole 应用程序就会打开多个选项卡。概览选项卡显示堆内存使用情况、线程、类、CPU 使用情况
方法六:通过编写程序使用HotSpotDiagnosticMBean
我们使用 HotSpotDiagnosticMBean 来调用堆转储操作。我们从 MBean 平台服务器获取 MBean 对象。在下面的示例中,我们使用反射来调用 MBean 对象的heapDump()方法。
例子
Java
// Java Program Invoking heapDump() Method of MBean Object
// Importing input output classes
import java.io.*;
// Main class
class GFG {
// Custom string passed as input
private static final String HOTSPOT_BEAN
= "com.sun.management:type=HotSpotDiagnostic";
// Private member variable of this class
private static volatile Object hotSpotMBean;
// Invoke this method when heap dump is to be generated
// @param fileName - name of the heap dump file
// @param live - indicates if only live objects are to
// be included in the heap dump
// Method 1
// To generate heap dumps
static void generateHeapDump(String fileName,
boolean live)
{
initHotspotMBean();
// Try block to check if any exceptions occurs
try {
Class clazz = Class.forName(
"com.sun.management.HotSpotDiagnosticMXBean");
Method m = clazz.getMethod(
"dumpHeap", String.class, boolean.class);
m.invoke(hotSpotMBean, fileName, live);
}
// Catch block handling runtime exceptions
catch (RuntimeException re) {
throw re;
}
catch (Exception exp) {
throw new RuntimeException(exp);
}
}
// Method 2
private static void initHotspotMBean()
{
if (hotSpotMBean == null) {
synchronized (JavaHeapDump.class)
{
if (hotSpotMBean == null) {
hotSpotMBean = getHotSpotMbean();
}
}
}
}
// Method 3
// To get the HOtSpotBean from the MBean server
private static Object getHotSpotMbean()
{
Object hotspotBean = null;
// Try block tocheck for exceptions
try {
// Loading using .forName() method
Class clazz = Class.forName(
"com.sun.management.HotSpotDiagnosticMXBean");
MBeanServer mbeanServer
= ManagementFactory
.getPlatformMBeanServer();
hotspotBean
= ManagementFactory.newPlatformMXBeanProxy(
mbeanServer, HOTSPOT_BEAN, clazz);
return hotspotBean;
}
// Catch block 1
// Handling exceptions if class not found
catch (ClassNotFoundException e) {
// Printthe exception along with line number
// using printStackTrace() method
e.printStackTrace();
}
// Catch block 2
// Handling basic I/O exceptions
catch (IOException e) {
// Printthe exception along with line number
// using printStackTrace() method
e.printStackTrace();
}
return hotspotBean;
}
// Method 4
// Main driver method
public static void main(String[] args)
{
// File taken as an input
String fileName
= "/home/suchitra/Desktop/suchitra/projects/java-concurrency-examples/JavaHeapDumpGenerator/src/heap1.hprof";
// Flag variable set to true
boolean live = true;
// Switch case
switch (args.length) {
case 2:
live = args[1].equals("true");
case 1:
fileName = args[0];
}
// Calling Method 1 in main() method to
// generate heap dumps
generateHeapDump(fileName, live);
}
}
Note:
We run this application by passing command-line arguments for file path where the heap dump is to be generated and live parameter which can be set as true or false. When this java code is run, it generates a heap1.hprof file in src folder. This heap dump can be analyzed using MAT(Memory Analyzer Tool). This can be installed as a plugin in Eclipse from Marketplace.
- 现在最后让我们在 JVisualVM 的帮助下分析堆转储文件。
- 生成堆转储文件后,我们使用 JVisualVM 之类的工具来分析该文件。当您打开堆转储时, Java VisualVM 默认显示摘要视图。 “摘要”视图显示进行堆转储的运行环境和其他系统属性。
- 在 JvisualVM 中,我们转到File -> Load并选择生成“.hprof 文件”的文件夹位置,下面以图形方式提供帮助,以便对其有一个公平的理解。