当前位置 : 主页 > 网络编程 > PHP >

线上OOM:GC Overhead Limit Exceeded异常排查(二)

来源:互联网 收集:自由互联 发布时间:2023-10-08
一、Java的内存模型 《Java虚拟机规范》规定虚拟机包括以下几个运行时数据区: 方法区 - Method Area 虚拟机栈 - VM Stack 本地方法栈 - Native Method Stack 堆 - Heap 程序计数器 - Program Counter Reg

一、Java的内存模型

《Java虚拟机规范》规定虚拟机包括以下几个运行时数据区:

  1. 方法区 - Method Area
  2. 虚拟机栈 - VM Stack
  3. 本地方法栈 - Native Method Stack
  4. 堆 - Heap
  5. 程序计数器 - Program Counter Register

线上OOM:GC Overhead Limit Exceeded异常排查(二)_内存泄露

在不同的​​JVM​​运行时实现中可能存在差异

常见的​​JVM​​运行时有:

  1. OracleJDK
  2. OpenJDK
  3. IBM J9
  4. JRocket
  5. Alibaba Dragonwell
  6. Tencent Kona
  7. Graalvm

比如​​OracleJDK8​​的方法区区叫元空间,具体不再展开...

不考虑差异性,本文主旨是线上​​OracleJDK8​​说明内存溢出出现的场景,排查方式和解决方案

二、内存溢出类型

  1. StackOverflowError
  2. OutOfMemoryError

​StackOverflowError​​​当线程栈深度超过设置的最大深度,则由虚拟机抛出 ​​OutOfMemoryError​​当无法通过JVM申请到内存时,则由虚拟机抛出

除了程序计数器外,栈、堆、非堆(直接内存)都可以抛出​​OOM​

常见的异常错误及通用解:

  1. java.lang.StackOverflowError : Thread Stack space

原因:当线程栈深度超过设置的最大深度,则由虚拟机抛出

解决:

1)使用循环替换递归

2)使用调度器MapReduce思想来实现分之归并

  1. java.lang.OutOfMemoryError: Java heap space

原因:当前线程无法从JVM申请堆内存空间

解决:

1)具体问题具体分析,当定位到是大对象时,需要优化代码为小对象

2)当定位到是堆内存空间太小,修改VM配置。这里需评估并发量,经过压测和优化后得出

3)优化代码,减少处理耗时,如果是高耗时操作,可以在对象不使用后,去掉局部变量对大对象的引用

4)当定位到是内存泄露,则需要修改泄露代码(通常在引用第三方包出现)

  1. java.lang.OutOfMemoryError: Requested array size exceeds VM limit

原因:申请数组大小超过JVM允许值,不同JVM版本存在差异

解决:

1) 修改申请数组小大

  1. java.lang.OutOfMemoryError: GC Overhead Limit Exceeded

原因:当 GC 为释放很小空间占用大量时间时抛出,通常会伴随着CPU100%异常,线上系统严重卡顿

解决:跟​​Java heap space​​处理方法一样

  1. java.lang.OutOfMemoryError: Metaspace

原因:当前线程无法从JVM申请元空间内存,JDK8之后原永久代中的类元数据迁移到元空间(堆 -> 直接内存),常量池继续在堆中

解决:

1)当定位到是元空间设置太小,修改配置

2)当定位到是内存泄露,则修改代码(通常在引用第三方包出现)

  1. java.lang.OutOfMemoryError: Direct buffer memory

原因:一般是工具为了做零拷贝,直接将数据存储在直接内存中,减少用户态和内核态内存拷贝,当未做内存回收时,空间不释放,抛出异常

解决:

1)定位到直接内存设置太小,修改配置

2)定位到内存泄露未释放内存,则修改异常代码

3)定位到​​Metaspace​​未设置大小,该空间内存泄露,则修改异常代码

疑难借助工具排查:

  1. VisualVM
  2. Eclipse MAT(Memory Analyzer Tool)
  3. Alibab Arthas
上一篇:机器人建图、感知和交互的语义研究综述
下一篇:没有了
网友评论