找回密码
 立即注册

QQ登录

只需一步,快速开始

工控课堂 首页 工控文库 上位机编程 查看内容

Java内存溢出(OOM)分析

2022-9-18 14:45| 发布者: gk-auto| 查看: 652| 评论: 0|来自: 博客园

摘要: 当JVM内存不足时,会抛出java.lang.OutOfMemoryError.主要的OOM类型右:Java heap space:堆空间不足GC overhead limit exceeded : GC开销超出限制Permgen space:永久代内存不足Metaspace:元空间内存不足Unable to ...
当JVM内存不足时,会抛出java.lang.OutOfMemoryError.
 
主要的OOM类型右:
  • Java heap space:堆空间不足
  • GC overhead limit exceeded : GC开销超出限制
  • Permgen space:永久代内存不足
  • Metaspace:元空间内存不足
  • Unable to create new native thread:无法创建新的本地线程
  • Out of swap space? : 交换空间内存不足
  • Kill process or sacrifice child

 

Java heap space:堆空间不足

  • 通用解决方案:通过-Xmx设置更大的堆内存【该方式可能只是延迟报错的发生,如果不能从根本上找到原因,报错还是可能会发生】
  • 进一步原因分析及解决方案:
    • 流量/数据量峰值 : 可以考虑添加机器资源,或者做限流
    • 内存泄漏 : 需要找到持有的对象,修改代码
    • 创建了一个超大对象(通常是一个大数组) : 可以进行业务切分
  • 代码示例
    • 内存泄漏【-Xmx10m】
 View Code
 View Result
    • 创建了一个超大对象
 View Code
 View Result[-Xmx12m]
 View Result[-Xmx35m]

 

GC overhead limit exceeded : GC开销超出限制

默认情况下,当应用程序花费超过98%的时间用来做GC并且回收了不到2%的堆内存时,会抛出java.lang.OutOfMemoryError:GC overhead limit exceeded错误。
此类问题的原因与解决方案跟 Java heap space 非常类似,可以参考上文
  • 代码演示【使用默认的VM配置】
 View Code
 View Result

 

Permgen space:永久代内存不足
  • 背景:永久代主要存储类的信息,比如:类加载引用、运行时常量池、字段、方法等。因此,Permgen的大小取决于被加载类的数量及类的大小。
  • 原因:
    • 加载了太多的类
    • 加载了超大类
  • 注意:JDK8已经完全移除永久代空间,取而代之的是元空间(Metaspace)

 

Metaspace:元空间内存不足
  • 背景:Metaspace存储类的元数据信息
  • 原因:
    • 加载了太多的类
    • 加载了超大类
  • 解决方案
    • 调整-XX:MaxMetaspaceSize参数
    • 删除-XX:MaxMetaspaceSize参数,解除限制【默认是没有限制的。默认情况下,对于64位服务器端JVM,MetaspaceSize默认大小是21M(初始限制值),一旦达到这个限制值,FullGC将被触发进行类卸载,并且这个限制值将会被重置,新的限制值依赖于Metaspace的剩余容量。如果没有足够空间被释放,这个限制值将会上升。】
  • 代码演示【JDK1.8】
 View Code
 View Result

 

Unable to create new native thread:无法创建新的本地线程
  •  背景:每个线程都需要一定的内存空间,当JVM向底层操作系统请求创建一个新的native线程时,如果没有足够的资源分配就会报这个错误
  • 原因分析及解决方案:
    • 线程数超过了OS最大线程数ulimit限制 : 调高 OS 层面的线程最大数 - 执行 ulimia-a 查看最大线程数限制,使用 ulimit-u xxx 调整最大线程数限制
    • 线程数超过了本地线程最大数:限制线程池大小  ; 
    • native内存不足 : 
      • 使用 -Xss 参数减少线程栈的大小
      • 升级配置,为机器提供更多的内存
  • 代码示例
 View Code
 View Result

 

Out of swap space? : 交换空间内存不足
  • 背景:虚拟内存(Virtual Memory)由物理内存(Physical Memory)和交换空间(Swap Space)两部分组成。在JVM请求的总内存大于可用物理内存的情况下,操作系统会将内存中的数据交换到磁盘上去。当交换空间也将耗尽时就会报 Outof swap space? 错误。
  • 原因分析及解决方案:【往往是由操作系统级别的问题引起的】
    • 操作系统配置的交换空间不足 :
      •  加交换空间【对交换空间运行垃圾回收算法会使GC暂停的时间增加几个数量级,因此使用增加交换空间的方法】
      • 升级机器以包含更多内存
    • 系统上的另一个进程消耗所有内存资源:如果应用部署在JVM需要同其他进程激烈竞争获取资源的物理机上,建议将服务隔离到单独的虚拟机中
    • 本地内存泄漏导致应用程序失败: 优化应用程序以减少其内存占用
 
Kill process or sacrifice child
  • 背景:操作系统是建立在进程的概念之上,这些进程在内核中作业,其中有一个非常特殊的进程,名叫“内存杀手(Out of memory killer)”。当内核检测到系统内存不足时,OOM killer被激活,然后选择一个进程杀掉。
  • 原因分析:程序占用大量系统内存导致其他进程没有可用内存
  • 解决方案:
    • 调整OOM Killer配置
    • 升级机器以包含更多内存
 
你可以通过修改各种启动参数来“快速修复”这些内存溢出错误,但你需要正确区分你是否只是推迟或者隐藏了java.lang.OutOfMemoryError的症状。如果你的应用程序确实存在内存泄漏或者本来就加载了一些不合理的类,那么所有这些配置都只是推迟问题出现的时间而已,实际也不会改善任何东西。
 
 
参考文献:
关注公众号,加入500人微信群,下载100G免费资料!

最新评论

热门文章
关闭

站长推荐上一条 /1 下一条

QQ|手机版|免责声明|本站介绍|工控课堂 ( 沪ICP备20008691号-1 )

GMT+8, 2025-12-23 01:25 , Processed in 0.207355 second(s), 23 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

返回顶部