内存溢出是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于虚拟机能提供的最大内存。 引起内存溢出的原因有很多种,常见的有以下几种:
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回收。