内存溢出是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于虚拟机能提供的最大内存。
引起内存溢出的原因有很多种,常见的有以下几种:
public class Main {
public static void main(String[] args) {
List<Main> list = new ArrayList<>();
while (true) {
list.add(new Main());
}
}
}
-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=C:\Users\yanyunfan\Desktop
我们通过-xms20m -Xmx20m两个参数,限制了Java堆的大小为20MB,不可扩展,后两个参数控制了当出现了OutOfMemoryError时,会Dump出当前内存的堆转储快照,并保存到指定位置中。
去桌面找到dump文件,java_pid24096.hprof。
打开JDK自带的工具VisualVM,装入文件。
面板切换到"类"
这里可以很直观的看出,OutOfMemoryError产生的原因,是Main这个对象导致的。
首先我们要排除内存泄露,即我们不需要的对象没有被回收掉。我们要找到泄漏的对象是如何与GC Root进行关联的?从而准确定位出泄漏代码的位置,然后进行修改。
如果不是内存泄漏,即堆中的对象必须存活,这个时候,我们可以通过调节虚拟机的堆参数(-Xms -Xmx),适当调大堆内存。但是在此之前,我们一定要检查一下代码是否存在优化的空间,如:是否存在某些对象的生命周期过长?是否可以使用享元模式减少对象数量?等等
内存溢出的解决方案:
(1)修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)
(2)检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。
(3)对代码进行走查和分析,找出可能发生内存溢出的位置。
(4)使用内存查看工具动态查看内存使用情况
重点排查以下几点:
(1)检查对数据库查询中,是否有一次获得全部数据的查询。线下测的没问题,一到线上数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
(2)检查代码中是否有死循环或递归调用。
(3)检查是否有大循环重复产生新对象实体。
(4)检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://yunfan.blog.csdn.net/article/details/121189770
内容来源于网络,如有侵权,请联系作者删除!