线上发生OOM
作者:互联网
线上jvm故障处理思路
报错分类
java.lang.OutOfMemoryError: Java heap space ------>java堆内存溢出
此种情况最常见,一般由于内存泄露或者堆的大小设置不当引起。对于内存泄露,需要通过内存监控软件查找程序中的泄露代码,而堆大小可以通过虚拟机参数-Xms,-Xmx等修改。
java.lang.OutOfMemoryError: PermGen space 或 java.lang.OutOfMemoryError:MetaSpace ------>java方法区
(java8 元空间)溢出了,一般出现于大量Class或者jsp页面,或者采用cglib等反射机制的情况,因为上述情况会产生大量的Class信息存储于方法区。此种情况可以通过更改方法区的大小来解决,使用类似-XX:PermSize=64m -XX:MaxPermSize=256m的形式修改。另外,过多的常量尤其是字符串也会导致方法区溢出。
java.lang.StackOverflowError ------> 不会抛OOM error,但也是比较常见的Java内存溢出。
JAVA虚拟机栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,栈大小设置太小也会出现此种溢出。可以通过虚拟机参数-Xss来设置栈的大小。
首先说明:在此不是解决上线bug或者容器崩溃的错误,而是解决OutOfMemoryError与StackOverflowError,出现了这个错误,虚拟机不能用,但是要里面恢复,针对这样的问题,我们来聊聊一些处理的办法,结合我们前面学习的虚拟机的配置与工具的使用,进行实战整理。
-
线上出现访问很慢、超时、或者有的直接报错运行时的错误,我们看到错误信息,根据状态去定位。检查是否是网络问题 (cdn,dns,nginx),运维应该快速的排查。
-
检查jvm时候正常工作,检查日志是否有遭难性的错误,如果jvm进程正常,应用中出现了灾难性的,那就应用程序的性能问题或者bug,赶紧加班去吧。
-
前面这个过程很快要完成,估计在问题出现的30’就的搞定,搞不定估计老老大要出面了,如果问题确定是开发的问题,日志给开发,重启应用服务,开发解决问题,发布bug版本。
保存状态信息
jmap -dump:format=b,file=/tmp/logs/dump.phrof 14632 #生成转储存快照 dump 文件(最为常用)
jmap -heap 14632 > /tmp/logs/heap.log
jstat -gcutil 14632 > /tmp/logs/stat.log
jstack -l 14632 > /tmp/logs/stack.log
jmap(堆内存分析)
一定要注意,触发Full GC和不触发Full GC的情况,因为我们必须要通过控制变量法,对照地来实验结果。当堆异常时,想要获得快照,如此时使用GC后快照,则必然会破坏当前的堆样本。因此,我们针对堆 heap 的分析,必定是需要2份以上快照,1份是有问题的 heap dump,通常是异常下未GC的情况;另一份是项目启动后输出,或GC后输出的比较正常的 heap dump。
生成转储存快照 dump 文件(最为常用)!
jmap -dump:format=b,file=/dump.phrof pid
jstack(栈分析)
jstack -l pid >/var/thread.txt
获取 Thread dump,并输出到 /var/thread.txt 文件
jps(显进程信息)
jps -v
显示Java进程ID 和 类的名称, 以及传递给JVM的启动参数等
jstat(查看GC相关信息)
jstat -gcutil pid
详细显示GC相关的堆信息,查看GC的次数,及时间(非常实用)
jinfo( 动态 JVM 参数控制)
jinfo flags pid
所有的vm参数设置的值,可看垃圾回收器的种类
jhat(分析 heapdump 文件)
jhat -J-Xmx2048M heap.phrof
可以将堆中的对象以html的形式显示出来,包括对象的数量,大小等等,并支持对象查询语言(当然,能拿到 dump 文件,还是推荐拿到本地使用工具来查看,而不是在服务器上直接查看)。
-J 后可以跟 JVM 的参数;
jvm堆常用参数
参数 | 描述 |
---|---|
-Xms | 堆内存初始大小,单位m、g(堆内存下限) |
-Xmx(MaxHeapSize) | 堆内存最大允许大小,一般不要大于物理内存的80%(堆内存上限) |
-XX:PermSize | 非堆内存初始大小,一般应用设置初始化200m,最大1024m就够了 (元数据区初始) |
-XX:MaxPermSize | 非堆内存最大允许大小(元数据最大值) |
-XX:NewSize(-Xns) | 年轻代内存初始大小(一般小于Xms) |
-XX:MaxNewSize(-Xmn) | 年轻代内存最大允许大小,也可以缩写(一般小于Xmx) |
-XX:SurvivorRatio=8 | 年轻代中Eden区与Survivor区的容量比例值,默认为8,即8:1 |
-Xss | 堆栈内存大小 |
-XX:NewRatio | 新生代与老年代的比率 默认是2,老年代是新生代的2倍 |
根据日志信息排查问题
根据stat与heap区情况,可以大概的定位到是哪个区域发生了,通常老说是老年代,为什么,因为新生代在空间不足的情况下会触发GC,如果一直不足,一直GC,那么分配的对象很快就进入老年代,而又得不到释放。那么我们就需要检查哪些对象比较大。根据jstack信息,找到运行的线程以及可能报错的线程位置,Dump文件查看哪些对象较多较大
Jprofiler持续跟踪重启后的内存使用,对象分配,线程运行情况,基本上来说可以定位到错误的地方。
这样如果还找不到问题,那可能太隐蔽了,需要把相关的人召集起来,针对问题,集中解决,知道问题最终解决。
如有侵权联系邮箱:1757710613@qq.com
标签:java,dump,OOM,发生,XX,GC,线上,heap,内存 来源: https://www.cnblogs.com/l0vE/p/15934772.html