1.什么是内存溢出?在哪些区域会发生内存溢出
内存溢出指程序申请内存时,没有足够的内存供申请者使用
第一块Metaspace区域里可能发生OOM
第二块可能发生OOM的区域,就是每个线程的虚拟机栈内存。
第三块可能发生内存溢出的区域,就是堆内存空间!
2.Metaspace区域是如何触发内存溢出的?
如下两个参数就是用来设置Metaspace区域大小的:
-XX:MetaspaceSize=512m
-XX:MaxMetaspaceSize=512m
Metaspace区域满了,此时会触发Full GC,连带着回收Metaspace里的类。但是类被回收前提是有三个条件的,满足不了三个条件回收不了多少类,此时你的JVM还在拼命的加载类放到Metaspace里去就会引发内存溢出的问题。
3.到底什么情况下会发生Metaspace内存溢出?
Metaspace这块区域一般很少发生内存溢出,如果发生内存溢出一般都是因为两个原因:
- 在上线系统的时候对Metaspace区域直接用默认的参数,即根本不设置其大小这会导致默认的Metaspace区域可能才几十MB而已
- 系统的时候会用cglib之类的技术动态生成一些类,一旦代码中没有控制好,导致你生成的类过于多的时候,就很容易把Metaspace给塞满,进而引发内存溢出
怎么解决?
对于第一种问题,通常来说,有经验的工程师上线系统往往会设置对应的Metaspace大小,推荐的值在512MB那样,一般都是足够的。
4什么情况下会发生线程的栈内存溢出?
每次方法调用的栈桢都是要占用内存的,一个线程调用多个方法的会入栈和出栈
既然一个线程的虚拟机栈内存大小是有限的,比如1MB,那么假设你不停的让这个线程去调用各种方法,然后不停的把方法调用的栈桢压入栈中,此时终有一个时刻,大量的栈桢会消耗完毕这个1MB的线程栈内存,最终就会导致出现栈内存溢出的情况。
无限制的方法递归
5.到底什么情况下会发生堆内存溢出?
- 系统承载高并发请求,因为请求量过大,导致大量对象都是存活的,所以要继续放入新的对象实在是不行了,此时就会引发OOM系统崩溃
- 系统有内存泄漏的问题,就是莫名其妙弄了很多的对象,结果对象都是存活的,没有及时取消对他们的引用,导致触发GC还是无法回收,此时只能引发内存溢出,因为内存实在放不下更多对象了
因此总结起来,一般引发OOM,要不然是系统负载过高,要不然就是有内存泄漏的问题
6如何在JVM内存溢出的时候自动dump内存快照?
-
在OOM的时候自动dump内存快照
在JVM的启动参数中加入如下的一些参数:-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/usr/local/app/oom
第一个参数意思是在OOM的时候自动dump内存快照出来,第二个参数是说把内存快照放到哪儿去 -
发生OOM,用MAT工具来分析Metaspace、栈内存、堆内存三种内存溢出下的内存快照文件
7.如何对对线上系统的OOM异常进行监控和报警
一种是通过监控系统,一种是被动等待系统挂掉后客服来通知你
8.堆内存溢出的问题如何分析和定位?
- 必须在JVM参数中加入自动导出内存快照,一个是到线上看一下日志文件里的报错,如果是堆溢出,立马用MAT分析内存快照。
- 先看占用内存最多的对象是谁,然后分析那个线程的调用栈,接着就可以看到是哪个方法引发的内存溢出了接着优化代码即可。