JVM堆内存转储

本文介绍了JVM堆转储的概念,包括手动使用jcmd工具进行堆转储和配置自动在内存溢出时进行转储的方法,以及注意事项如文件路径设置。

堆转储是 JVM 中特定时刻内存中的所有对象的快照。它们对于解决内存泄漏问题并优化 Java 应用程序中的内存使用情况非常有用。

堆转储通常以二进制格式 hprof 文件存储。我们可以使用 jhat 或 JVisualVM 等工具打开和分析这些文件。

下面介绍两种堆转储的方式:

1. JCMD

  jcmd 是一个非常完整的工具,它通过向 JVM 发送命令请求来工作。我们必须在运行 Java 进程的同一台计算机上使用它。

  其众多命令之一是 GC.heap_dump。我们只需指定进程的 pid 和输出文件路径,就可以使用它来获取堆转储:

jcmd <pid> GC.heap_dump <file-path>

  例如:

[root@cwy-hbcsh-zyl-1 HDTool]# jps
22387 jar
17925 jar
13383 jar
26682 Jps
21422 jar
[root@cwy-hbcsh-zyl-1 HDTool]# jcmd 17925 GC.heap_dump /opt/HDTool/dump.hprof
17925:
Heap dump file created
[root@cwy-hbcsh-zyl-1 HDTool]#

2. 自动捕捉head dump

  上面工具jcmd旨在在特定时间手动捕获堆转储。在某些情况下,我们希望在发生内存溢出错误 java.lang.OutOfMemoryError 时, JVM自动执行堆内存转储,以方便事后进行排查和分析。

  JVM提供了一个命令行启动参数 HeapDumpOnOutOfMemoryError, 使用的格式为:

java -XX:+HeapDumpOnOutOfMemoryError
  • 如果不用 HeapDumpPath 选项指定转储路径,则会自动保存到启动目录下,文件名的格式为: 
java_pid<pid>.hprof
  • 指定 HeapDumpPath 参数的使用示例如下:
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<file-or-dir-path>

   对于某个应用服务,启动脚本中设置内存溢出转储路径为/opt/logs/app。如下:

特别说明:不建议内存溢出文件名写死,建议只写路径;否则,再次发生内存溢出,内存溢出文件无法成功保存。

   如下:文件命名为heapdump.hprof,下次发生内存溢出,再次生成的heapdump.hprof无法保存。

   无法保存的提示如下:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to /opt/logs/app/heapdump.hprof ...
Unable to create /opt/logs/app/heapdump.hprof: 文件已存在
### 如何分析JVM转储文件以诊断内存问题或性能瓶颈 #### 使用工具MAT分析堆转储文件 当需要分析JVM转储文件时,常用的工具有Eclipse Memory Analyzer Tool (MAT),它能够高效地解析和展示堆转储中的数据。通过支配树功能或者直方图功能,可以快速识别哪些类型的对象占用了最多的内存[^3]。 #### 配置生成堆转储文件的方式 为了获取堆转储文件以便后续分析,可以通过两种主要途径完成: 1. **自动触发**:在启动Java应用时设置`-XX:+HeapDumpOnOutOfMemoryError`参数,这使得一旦发生`OutOfMemoryError`错误,JVM会自动生成堆转储文件到当前的工作目录下[^2]。 2. **手动生成**:利用命令行工具如`jmap`,即使未达到OOM状态也可以随时生成heap dump文件。例如运行如下命令即可针对指定PID的应用创建dump文件: ```bash jmap -dump:live,format=b,file=heap_dump.hprof <pid> ``` 其中`<pid>`代表目标进程ID[^4]。 #### 实际案例演示 考虑一段模拟数据库查询结果加载至内存的简单代码片段,在此场景下可能会因为字符串处理不当而导致严重的内存泄漏风险: ```java import java.util.Random; import java.util.concurrent.TimeUnit; public class StringInternTest { static final int MAX = 1000 * 10000; static final String[] arr = new String[MAX]; public static void main(String[] args) throws InterruptedException { Integer[] DB_DATA = new Integer[10]; Random random = new Random(10 * 10000); for(int i = 0;i < DB_DATA.length;i++) { DB_DATA[i]=random.nextInt(); } long t = System.currentTimeMillis(); for(int i = 0;i < MAX;i++) { // 不调用 intern() arr[i] = new String(String.valueOf(DB_DATA[i % DB_DATA.length])); /* 调用 intern() 可能加剧内存压力 */ // arr[i] = new String(String.valueOf(DB_DATA[i % DB_DATA.length])).intern(); } System.out.println((System.currentTimeMillis()-t)+"ms"); System.gc(); TimeUnit.SECONDS.sleep(25); // 提供时间窗口用于外部监控/调试操作 } } ``` 执行上述程序后如果怀疑存在潜在的内存管理问题,则可按照前述步骤导出对应的heap dump文件,并借助MAT进一步深入剖析具体哪部分代码造成了不必要的资源占用情况。 #### 总结 综上所述,无论是预防性的定期审查还是响应式的故障排查,掌握如何有效运用像MAT这样的专业级软件包都是至关重要的技能之一。通过对收集来的heap dumps进行全面细致的研究,开发人员不仅能够发现现有系统的薄弱环节所在之处,而且还能据此制定相应的优化策略从而提升整体效率表现。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值