通常jvm程序消失,或者内存占用过大
1.java程序占用内存过大,被操作系统杀掉
2.java程序出现OOM
出现OOM首先要拿到HeapDump日志信息
有以下方法:
- java运行中添加-XX:HeapDumpOnOutMemoryError参数
- jmap -dump:live,live,format=b,file="路径" pid
(pid可以通过jps获取) 可以获取正在运行堆栈信息,但jmap都在线上运行会影响线上线程,所以可在测试环境下进行重现方式 - 使用阿里的 arthas https://arthas.aliyun.com/doc/quick-start.html
使用步骤:
curl -O https://arthas.aliyun.com/arthas-boot.jar
#显示全部进程 选择需要观察的序号
java -jar arthas-boot.jar
#选了序号后 等待片刻进入目标进程
#dump到指定文件
heapdump /tmp/dump.hprof
#只dump live对象
heapdump --live /tmp/dump.hprof
#介绍几个其他常用的指令
dashboard #展示当前进程的信息
thread id #打印线程ID的栈信息
thread -b #可以查看方便查看死锁
jad *.class #可以获取class的反编译代码相关信息,如下。
[arthas@961]$ jad TestOutMemory
ClassLoader:
+-sun.misc.Launcher$AppClassLoader@73d16e93
+-sun.misc.Launcher$ExtClassLoader@a2c976a
Location:
/mnt/prepare/java/
/*
* Decompiled with CFR.
*/
import java.util.HashMap;
public class TestOutMemory {
public static void main(String[] arrstring) throws InterruptedException {
HashMap<Integer, byte[]> hashMap = new HashMap<Integer, byte[]>();
for (int i = 1000; i > 0; --i) {
Thread.sleep(1000L);
hashMap.put(i, new byte[0x100000]);
}
}
}
Affect(row-cnt:1) cost in 86 ms.
那么这个除了反编译还有什么作用,可以进行热修改。见这篇文章
HiroLin:小白java系列-使用阿里arthas进行线上热更新zhuanlan.zhihu.com对日志进行分析
有如下工具:
- jvisualvm
- EAT (Eclipse Memory Analyzer Tool) 可单独下载http://www.eclipse.org/mat/downloads.php
- jprofiler(收费)
重现OOM定位
代码:
package com.hiro.learn.outMemory;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/**
* Project: learn
*
* @author : hirolin
* @date : 2020/10/8 17:39
*/
public class TestOutMemory {
public static void main(String[] args) throws InterruptedException {
Map temp = new HashMap();
for (int i = 1000; i > 0; i--) {
Thread.sleep(500);
System.out.println(i);
temp.put(i, new byte[1024 * 1024]);//生产1M的占用
}
}
}
那么如果指定当前堆大小, -Xmx10M -Xms10M -XX:+HeapDumpOnOutOfMemoryError
堆得最大最小大小最好设置一样,避免堆内存分配或大或小抖动,当然根据实际场景合理设置
那么在循环10次左右就会oom,且无法回收。控制台输出如下:
1000
999
998
997
996
995
994
993
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid23784.hprof ...
Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceHeap dump file created [8867828 bytes in 0.050 secs]
可以看到内存溢出溢出:堆满了,泄露:内存中存在一直不会被回收的区域
使用idea设置headdump文件,文件生成后在工程当前目前下。
- 此时使用jvisualvm打开java_pid23784.hprof文件。
可以看到byte占用最高。
- EMT更为详细信息
通常我主要看这两个tap。histogram和leak suspects
可以看到占用最大内存对象引用情况,方便定位到源头。
第二个是推测可能出现问题的地方:
可以看到上述已经描述了有一个本地变量一直占用了内存,对应代码中的byte处问题。