共计 2623 个字符,预计需要花费 7 分钟才能阅读完成。
实验应用:
创建
vim MemoryLeakDemo.java
OutOfMemoryError 异常。
import java.util.List;
import java.util.ArrayList;
public class MemoryLeakDemo {
private static List<String> memoryLeakList = new ArrayList<>();
public static void main(String[] args) {
while (true) {
memoryLeakList.add(new String(new char[1024 * 1024])); // 1MB string
try {
Thread.sleep(100); // Sleep for 100ms
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
编译
javac MemoryLeakDemo.java
运行
java MemoryLeakDemo
离线文件分析
监控调参
java -Xmx128m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump.hprof MemoryLeakDemo
这里,-Xmx128m限制了最大堆内存大小为 128MB,-XX:+HeapDumpOnOutOfMemoryError会在发生内存溢出错误时自动创建堆转储文件,-XX:HeapDumpPath指定了堆转储文件的路径。
但是正式环境使用的时候不要加这个参数,不然在内存快满的时候总是会生成 dump 而导致 jvm 卡半天,需要调试的时候才需要加这个参数
注意:通过 WAS 生成的 PHD 文件 dump 不能分析出出问题的模板,因为 PHD 文件不包含对象的值内容,无法根据 PHD 文件找到出问题的模板,所以 PHD 文件没有太大的参考价值
下载文件到客户端
sz -y dump.hprof
双击.hprof 文件

远程安装监控
下载软件
wget https://download.ej-technologies.com/jprofiler/jprofiler_linux_14_0_3.tar.gz
tar -zxvf jprofiler_linux_14_0_2.tar.gz -C /usr/local/
修改环境变量
vim /etc/profile
JPROFILER_HOME=/usr/local/jprofiler14.0.2/bin/linux-x64
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$JPROFILER_HOME
source /etc/profile
新建远程集成







远程启动 java 应用

远程启动
分析
系统的内存消耗过多往往有以下几种原因:
1、频繁创建 Java 对象,如:数据库查询时,没分页,导致查出表中所有记录;代码中存在死循环或循环产生过多重复的对象实体; 2、存在大对象,如:读取文件时,不是边读边写而是先读到一个 byte 数组,这样如果读取的文件时 50M 则仅此一项操作就会占有 JVM50M 内存。 3、存在内存泄漏,导致已不被使用的对象不被 GC 回收,从而随着系统使用时间的增长,内存不断受到解压,最终 OutOfMemory。
内存溢出:第 1、2 中情况。程序向系统申请的内存空间超出了系统能给的。比如内存只能分配一个 int 类型,我却要塞给他一个 long 类型,系统就出现 oom。又比如一车最多能坐 5 个人,你却非要塞下 10 个,车就挤爆了。 内存泄漏:第 3 种情况。所谓内存泄漏是指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
针对 1、2 种情况,可以通过 Live Memory 视图来分析

首先通过观察 Size 列可以找到系统中占用内存最大的对象,然后再分析 Instance count 列. 如果 Size 过大并且它对应的 Instance Count 比较小则说明该对象是大对象,如果 Size 过大同时它对应的 Instance Count 也很大,着说明这个对象再被频繁创建,这时可以对应 Name 列指示的 Java 类路径找到项目里的 Java 类进行分析,如果发现有不合理的地方则改之。 在该视图下方的 Recorded Objects 子视图可以记录对象,从而查看类在一段时间里的总共实例数、GC 数和活动数,但是在使用这些功能时会导致系统的性能严重降低,例如:没开此功能时,1000 并发响应时间为 1s,开此功能后 500 并发时响应时间才能达到 1s,因此只有当存在内存泄漏时才开启该功能。
针对第 3 中情况, 如果怀疑内存泄漏的第一步就是查看“Memory” 和 ”Recorded objects”遥感勘测视图。当应用程序出现内存泄漏时,视图中会显示出带有震荡的线性积极趋势。大多数的内存泄漏可以被追溯到对象集群。这将产生一些大的 retained size 的对象。最大的对象视图列出了带有最大 retained size 的对象。你可以利用该树形向下钻取从而发现错误引用。

在 Memory 中可以指导 JVM 的总共内存分配大小、内存占用大小和内存空闲大小以及 GC 后内存占用的变化。蓝色区域表示占用的内存。当蓝色有下降表示此时刻可能经历了一次 GC。当发现 GC 后回收的力度越来越小,则说明很有可能存在内存泄漏。