首页 > 其他分享 >常见OOM问题之GC overhead limit exceeded 问题详解

常见OOM问题之GC overhead limit exceeded 问题详解

时间:2024-01-09 10:05:00浏览次数:27  
标签:lang java OOM Java GC JVM OutOfMemoryError overhead

Java 运行时环境包含一个内置的垃圾回收 (GC)进程。在许多其他编程语言中,开发人员需要手动分配和释放内存区域,以便可以重用释放的内存。

另一方面,Java 应用程序只需要分配内存。每当内存中的特定空间不再使用时,称为垃圾收集的单独进程会为它们清除内存。垃圾收集手册中更详细地解释了 GC 如何检测内存的特定部分,但您可以相信 GC 能很好地完成它的工作。

GC开销超过极限:java.lang.OutOfMemoryError时显示错误您的应用程序已经耗尽了几乎所有的可用内存和GC一再未能清除它

1.是什么原因造成的?

java.lang.OutOfMemoryError:GC开销超过极限误差信号,你的应用程序花费太多的时间做垃圾收集太少的结果JVM的方式。默认情况下,如果 JVM 花费超过98% 的总时间进行 GC 并且在 GC 之后仅回收不到 2% 的堆,则JVM 被配置为抛出此错误。


常见OOM问题之GC overhead limit exceeded 问题详解_垃圾回收

如果这个 GC 开销限制不存在,会发生什么?请注意java.lang.OutOfMemoryError: GC 开销限制超出错误仅在几次GC 循环后释放 2% 的内存时才会抛出。这意味着 GC 能够清理的少量堆可能会再次被快速填满,从而迫使 GC 再次重新启动清理过程。这形成了一个恶性循环,CPU 100% 忙于 GC,无法完成任何实际工作。应用程序的最终用户面临极端的减速——通常在几毫秒内完成的操作需要几分钟才能完成。

因此,“ java.lang.OutOfMemoryError: GC 开销限制超出”消息是快速失败原则的一个很好的例子。

2.举个例子

在以下示例中,我们通过初始化 Map 并在未终止的循环中将键值对添加到映射中来创建“超出 GC 开销限制”错误:

class Wrapper {
  public static void main(String args[]) throws Exception {
    Map map = System.getProperties();
    Random r = new Random();
    while (true) {
      map.put(r.nextInt(), "value");
    }
  }

正如您可能猜到的那样,这不会有好的结局。事实上,当我们启动上述程序时:

java -Xmx100m -XX:+UseParallelGC Wrapper

我们很快就会遇到java.lang.OutOfMemoryError: GC 开销限制超出消息。但是上面的例子很棘手。当使用不同的 Java 堆大小或不同的GC 算法启动时,我的 Mac OS X 10.9.2 和 Hotspot 1.7.0_45 将选择不同的死亡。例如,当我以较小的 Java 堆大小运行程序时,如下所示:

java -Xmx10m -XX:+UseParallelGC Wrapper

应用程序将因更常见的java.lang.OutOfMemoryError: Java heap space消息而死亡,该消息在 Map resize 时抛出。当我使用除ParallelGC之外的其他垃圾收集算法运行它时,例如-XX:+UseConcMarkSweepGC-XX:+UseG1GC,错误被默认异常处理程序捕获并且没有堆栈跟踪,因为堆已经耗尽到甚至无法在异常创建时填充堆栈跟踪。

这些变化确实是很好的例子,表明在资源受限的情况下,您无法预测应用程序的死亡方式,因此不要将您的期望建立在要完成的特定操作序列上。

3.解决办法是什么?

作为一个诙谐的解决方案,如果您只是想摆脱“ java.lang.OutOfMemoryError:GC开销限制超出”消息,将以下内容添加到您的启动脚本中即可实现:

-XX:-UseGCOverheadLimit

强烈建议不要使用这个选项——而不是解决问题,你只是推迟不可避免的问题:应用程序内存不足,需要修复。指定此选项只会用更熟悉的消息java.lang.OutOfMemoryError: Java heap space掩盖原始java.lang.OutOfMemoryError: GC 开销限制超出错误。

更严重的一点是 - 有时会触发 GC 开销限制错误,因为您分配给 JVM 的堆数量不足以满足在该 JVM 上运行的应用程序的需求。在这种情况下,你应该只分配更多的堆——请参阅本章末尾以了解如何实现这一点。

然而,在许多情况下,提供更多的 Java 堆空间并不能解决问题。例如,如果您的应用程序包含内存泄漏,添加更多堆只会推迟java.lang.OutOfMemoryError: Java heap space错误。此外,增加 Java 堆空间量也往往会增加影响应用程序吞吐量或延迟的GC 暂停时间。

如果您希望解决 Java 堆空间的潜在问题而不是掩盖症状,您需要弄清楚代码的哪一部分负责分配最多的内存。换句话说,您需要回答以下问题:

  1. 哪些对象占据堆的大部分
  2. 在源代码中分配这些对象的位置

此时,请确保在您的日历中清除几天(或 – 请参阅项目符号列表下方的自动方式)。以下是一个粗略的流程大纲,可以帮助您回答上述问题:

  • 从您的 JVM-to-troubleshoot 获取获取堆转储的许可。“转储”基本上是您可以分析的堆内容的快照,并包含应用程序在转储时保留在内存中的所有内容。包括密码、信用卡号等。
  • 指示您的 JVM 将其堆内存的内容转储到一个文件中。准备好进行一些转储,因为在错误的时间进行时,堆转储包含大量噪音,实际上可能毫无用处。另一方面,每个堆转储都会完全“冻结”JVM,所以不要太多,否则你的最终用户会开始发誓。
  • 找到一台可以加载转储的机器。当您的 JVM-to-troubleshoot 使用例如 8GB 的堆时,您需要一台超过 8GB 的机器来分析堆内容。启动转储分析软件(我们推荐Eclipse MAT,但也有同样好的替代品)。
  • 检测到最大堆消耗者的 GC 根的路径。我们已经覆盖在一个单独的后这一活动在这里。不用担心,一开始会觉得很麻烦,但经过几天的挖掘,你会好起来的。
  • 接下来,您需要弄清楚在源代码中的何处分配了具有潜在危险的大量对象。如果您对应用程序的源代码有很好的了解,则希望通过几次搜索就能做到这一点。当您运气不佳时,您将需要一些能量饮料来辅助。

或者,我们建议Plumbr,这是唯一具有自动根本原因检测功能的 Java 监控解决方案。在其他性能问题中,它捕获所有java.lang.OutOfMemoryError并自动为您提供有关最需要内存的数据结构的信息。它负责在幕后收集必要的数据——这包括有关堆使用情况的相关数据(只有对象布局图,没有实际数据),以及一些您甚至在堆转储中都找不到的数据。它还会为您进行必要的数据处理——在 JVM 遇到java.lang.OutOfMemoryError 时立即进行。这是来自 Plumbr 的java.lang.OutOfMemoryError事件警报示例:

常见OOM问题之GC overhead limit exceeded 问题详解_垃圾回收_02

无需任何额外的工具或分析,您就可以看到:

  • 哪些对象消耗的内存最多(271 个com.example.map.impl.PartitionContainer实例消耗了 248MB 总堆中的 173MB)
  • 这些对象的分配位置(大部分分配在MetricManagerImpl类中,第 304 行)
  • 当前引用这些对象的是什么(直到 GC 根的完整引用链)

有了这些信息,您就可以放大潜在的根本原因,并确保将数据结构修剪到适合您的内存池的级别。

但是,当您从内存分析或阅读 Plumbr 报告得出的结论是内存使用是合法的并且源代码中没有任何更改时,您需要让您的 JVM 有更多的 Java 堆空间才能正常运行。在这种情况下,更改您的 JVM 启动配置并在您的启动脚本中添加(或增加值,如果存在)仅一个参数:

java -Xmx1024m com.yourcompany.YourClass

在上面的例子中,Java 进程被分配了 1GB 的堆。修改最适合您的 JVM 的值。但是,如果结果是您的 JVM 仍然因 OutOfMemoryError 而死亡,您可能仍然无法避免上述手动或 Plumbr 辅助分析。

标签:lang,java,OOM,Java,GC,JVM,OutOfMemoryError,overhead
From: https://blog.51cto.com/u_16421711/9156547

相关文章

  • 闪速优选--五天学会SpringCloud实战
    本专栏带你用SpringCloudAlibaba搭建一套项目,让你五天掌握微服务的使用。微服务是很重要的技术,学会微服务会大大提升个人竞争力,大大提高简历筛选和面试通过率。项目名字:闪速优选。SpringCloudAlibaba在2020年之后的微服务项目中占主流,学它是最好的选择。教程地址:SpringCloud项目......
  • springcloud项项目使用脚本启动.sh,报错nested exception is org.apache.ibatis.excep
    问题:项目在使用java-jar启动每个jar包时,项目可正常访问,但要改为使用脚本,启动时,程序就报这个错了nestedexceptionisorg.apache.ibatis.exceptions.PersistenceException:###Errorqueryingdatabase.Cause:com.baomidou.dynamic.datasource.exception.CannotFindDataSource......
  • RuoYi-Cloud-Plus使用minio进行文件上传图片后无法预览解决_修改minio配置minio桶权限
     在文件管理的位置,发现刚刚上传的图片文件,会显示 预览图片失败 后来经过多方查看,发现是minio的配置的问题可以从这里:可以看到首先登录RuoYi-Cloud-Plus系统然后,打开文件管理页面可以看到,当上传了图片文件以后显示文件展示中,文件预览失败,那么这个时......
  • BegCode生成第一个应用,一键走起!
    BegCode生成应用的代码过程非常简单,只需要简单的几个问题就可以了。环境要求BegCode要求Node和Java环境,所以你首先要安装相应的工具。JDK版本1.8和17以上可选,Node.js需要18.18或20.6以上的版本。安装BegCodenpminstall-ggenerator-begcode运行并配置1.运行命令begcode样子有点......
  • RocketMQ系统性学习-SpringCloud Alibaba集成RocketMQ以及事务消息收发、最大重试消费
    欢迎关注公众号:【11来了】发送“资料”可以下载Redis、JVM系列文章PDF版本!作者为在读研究生,目前研二,计划在公众号记录学习常用中间件笔记,以及明年更新面试经历!事务消息收发流程如下:发送给MQ一条任务操作MQ的Broker成功收到后,那么发送方就开始执行原子db业务如果执行原子......
  • SpringCloud微服务实战——搭建企业级开发框架(三十二):代码生成器使用配置说明
    一、新建数据源配置  因考虑到多数据源问题,代码生成器作为一个通用的模块,后续可能会为其他工程生成代码,所以,这里不直接读取系统工程配置的数据源,而是让用户自己维护。参数说明数据源名称:用于查找区分数据源的名称连接地址:连接方式:数据库类型:数据库地址等参数,例:jdbc:m......
  • SpringCloud微服务实战——搭建企业级开发框架(三十一):自定义MybatisPlus代码生成器实现
      理想的情况下,代码生成可以节省很多重复且没有技术含量的工作量,并且代码生成可以按照统一的代码规范和格式来生成代码,给日常的代码开发提供很大的帮助。但是,代码生成也有其局限性,当牵涉到复杂的业务逻辑时,简单的代码生成功能无法解决。  目前市面上的代码生成器层出不穷,大多......
  • 一款神仙级SpringCloud微服务开源项目,接私活吊到不行!(附源码)
    今天给大家推荐一个牛逼的接私活项目,SpringCloud微服务架构项目!一个由商业级项目升级优化而来的微服务架构,采用SpringBoot2.7、SpringCloud等核心技术构建,提供基于React和Vue的两个前端框架用于快速搭建企业级的SaaS多租户微服务平台。架构图项目介绍采用前后端分离的模式......
  • RocketMQ系统性学习-SpringCloud Alibaba集成RocketMQ以及消息追踪、延时消息实战
    欢迎关注公众号:【11来了】发送“资料”可领取深入理解Redis系列文章结合电商场景讲解Redis使用场景、中间件系列笔记和编程高频电子书!作者为在读研究生,目前研二,计划在公众号记录学习常用中间件笔记,以及明年更新面试经历!消息追踪设置消息追踪需要修改broker启动的配置文件......
  • 特别策划:我们距AIGC的“奇点”还有多远?
    AIGC可能是当前科技圈最不容许忽视的趋势。根据咨询公司预测*,2023年中国AIGC产业规模约为143亿元,随着底层算力与大模型的完善,有望在2030年突破至惊人的万亿级。AIGC技术的落地正被无数双眼睛殷切关注着。在与商业价值联结最为紧密的应用层,生成式语音、图像及视频、虚拟数字人无不与......