在java的虚拟机异常中,有两个异常是你们比较关心的,一个是StackOverflowError,另外一个是OutOfMemoryError。今天咱们就来看看OutOfMemoryError是怎么产生的,以及如何去排查这个异常。java
要了解什么是OutOfMemoryError,咱们能够直接看一下OutOfMemoryError的源码,在类上的英文注释很好的阐述了什么是OutOfMemoryError,翻译过来的意思是,因为内存不足,虚拟机没有可分配的内存了,垃圾回收器也不能释放更多的内存。在生产环境中,因为访问量过大,把内存吃满,会出现OutOfMemoryError的异常,小伙伴们若是没有经验的话,每每一筹莫展,究竟是真的内存不够用了,仍是本身的程序有问题,也不知道如何去排查这样的异常。git
在这里,咱们写一段程序,来模拟一下OutOfMemoryError如何产生,咱们建立一个List对象,而后向里边不停的添加1M的Byte,以下;github
public static void main(String[] args) { List<Byte[]> list = new ArrayList<>(); int i = 0; try { while (true) { list.add(new Byte[1024 * 1024]); i++; } } catch (Throwable e) { e.printStackTrace(); System.out.println("执行了"+i+"次"); } }
咱们为了让程序运行时,快速的抛出OutOfMemoryError异常,能够在java的启动命令行增长启动参数,设置堆内存的初始值和最大值。这两个值在生产环境下,一般也是要配置的哦,要充分利用机器的内存嘛,若是不配置就会使用默认值。到时候因为内存不足向老板申请机器,可别挨骂哦~shell
那这两个参数怎么去加呢?工具
一般状况下,这两个值设置成同样就能够了,总之,咱们设置了堆内存的大小。咱们在IDEA的启动配置中,统一设置堆内存为80M,以下;spa
好了~~咱们运行一下,看看会不会抛出OutOfMemoryError异常吧命令行
java.lang.OutOfMemoryError: Java heap space at com.diancan.JavaOOMDemo.main(JavaOOMDemo.java:14) 执行了14次
执行了14次,抛出了OutOfMemoryError异常。可是,若是抛出这样一个异常,咱们怎么去排查呢?就这一行日志也看不出什么来啊。翻译
说到排查,若是咱们可以拿到异常时的内存快照,而后经过一些工具就能够了进行内存的分析了。那么咱们怎么去拿到内存溢出时的快照呢?其实,JDK也为咱们提供了这样的命令参数,咱们来看一下吧,日志
注意,HeapDumpPath的目录必定要手动建立好,若是没有这个目录,Dump会失败的。code
IDEA中的配置,如图:
咱们再运行一下程序,看看是什么样子,
java.lang.OutOfMemoryError: Java heap space Dumping heap to D:\heap-dump\java_pid24312.hprof ... Heap dump file created [123468648 bytes in 0.141 secs] java.lang.OutOfMemoryError: Java heap space at com.diancan.JavaOOMDemo.main(JavaOOMDemo.java:14) 执行了14次
咱们发现日志上面多了点东西,建立了一个文件,在D:\heap-dump\java_pid24312.hprof。这个文件就是咱们的内存快照。那么问题来了,咱们如何查看这个文件呢?直接打开是不行的,用写字板等也是不行的,那怎么办?其实也没那么复杂,使用JDK自带的jvisualvm就能够查看。
这里边有个小坑,若是你们用JDK8,能够在JDK的bin目录下找到jvisualvm.exe
,可是若是你使用的是JDK8以上的版本,就本示例中,使用的是JDK11,在bin目录下是找不到jvisualvm.exe
的。你们能够去visualvm的主页下载。
咱们启动visualvm,进入到以下的页面,
而后,点击左上角的加载快照按钮,而后选择刚才咱们Dump的文件,
咱们重点看一下右侧中间的部分,
类的实例大小排序,能够看到,咱们的Byte占了96.5%。详细的信息,咱们能够点进去看,包括变量里存的内容,这样咱们就能够很快的定位到内存溢出的位置,而且能够判断是真的内存不够了,仍是咱们的代码出了问题。