OOM发生的区域
1.Metaspace区域
当一次性加载的文件过多导致存储类信息的元空间区域内存不够用导致oom。
当Metaspace区域满了,此时会触发Full GC,1.7方法区也一样。FullGC同时也会回收类信息。 java.lang.OutOfMemoryError: Metaspace
条件:
首先该类的所有实例对象都已经从Java堆内存里被回收 其次加载这个类的ClassLoader已经被回收 最后,对该类的Class对象没有任何引用
发生OOM的情况:
1.使用默认的metaSpace的大小,如果系统大一点要依赖的jar很多那么默认的大小就是不够的
2.会用cglib之类的技术动态生成一些类,同时代码中没有控制好这个量就会塞满metaspace。
2.线程栈
在设置jvm参数的时候可以设置-Xss1M栈大小。如果方法调用链很长栈深度就会很大,到达一定深度的时候栈就不够用了,就会抛出java.lang.StackOverflowError
java中方法调用过程:
java执行的时候首先会给一个main线程栈,当调用方法的时候就会把那个方法装成一个栈帧压入线程栈,当方法执行完成后栈帧弹出。
什么情况下会出现OOM:
1.线程栈是有大小的,调用方法都会压一个栈帧进去,栈帧也是有大小的,当调用方法很多,又不返回就会耗尽栈内存
2.一个递归方法调用,不停的调用自己方法无法结束的时候也会OOM
3.虚拟机在动态扩展时无法申请到足够的内存,会抛出OOM(OutOfMemoryError)异常。
OOM(OutOfMemoryError)异常内存溢出:线程调用方法,创建方法该次调用的栈帧,内存不足抛出OOM异常。
3.堆内存
当对象放不下了,或者GC完了还有很多对象存活,下一个对象放不下的时候就会抛出OOM
java.lang.OutOfMemoryError: Java heap space
内存泄漏和内存溢出
内存泄漏Memory Leak:程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
一般出现内存泄漏的情况:长生命周期存活的对象,内部持有不使用对象的引用,导致不使用的垃圾对象无法回收。
一般程序经常出现内存泄漏的例子:在使用长期存活的数据结构、数组时,都要考虑对象引用导致内存泄漏的问题。
内存溢出(Out Of Memory,简称OOM):应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于能提供的最大内存。
结果:此时程序就运行不,系统会提示内存溢出(进程都会挂掉,情况严重)
线上OOM优化
1.Zabbix、Open-Falcon之类的监控平台,接入系统异常的一些监控和报警,你可以设置一旦系统出现了OOM异常,就发送报警给对应的开发人员,通过邮件、短信或者钉钉之类的IM工具。
2.生成jvm内存快照,通过MAT工具分析dump文件
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/usr/local/app/oom
3.jvm参数模板
-Xms4096M
-Xmx4096M
-Xmn3072M
-Xss 1M 栈大小
//元空间设置
-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=256M
//年轻代垃圾回收器
-XX:+UseParNewGC
//老年代垃圾回收器
-XX:+UseConcMarkSweepGC //使用cms的垃圾回收
-XX:CMSInitiatingOccupancyFaction=92 //老年代占92%时开始垃圾回收
-XX:+UseCMSCompactAtFullCollection //开启MSC算法压缩堆内存,与下面的参数配合使用
-XX:CMSFullGCsBeforeCompaction=0 //设置在执行多少次Full GC后对内存空间进行压缩整理。
-XX:+CMSParallelInitialMarkEnabled //开启并行标记
-XX:+CMSScavengeBeforeRemark //可以做到在重新标记前先执行一次新生代GC
-XX:+DisableExplicitGC //禁用System.gc
-XX:+PrintGCDetails -Xloggc:gc.log
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/usr/local/app/oom