当前位置: 首页 > news >正文

JVM源码剖析之Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded异常

写在前面:

版本信息:

jdk版本:jdk8u40
垃圾回收器:ParallelScavenge new/old

最近在群里看到有一位老哥拿着异常信息到处问,而发生的就是java.lang.OutOfMemoryError: GC overhead limit exceeded异常,恰好看到经常有人询问关于这个异常的问题,如何发生的,要如何解决呢?所以促使我写下这篇文章,此文章分为3大块,出现的原因,如何解决,源码论证。

异常出现的原因

full gc回收时间大于98%(这里是一个算法,可以忽略,只需要明白最近一直花大量时间在GC),并且回收后可用空间小于总空间的2%。 这样的情况下,达到5次就会抛出java.lang.OutOfMemoryError: GC overhead limit exceeded异常。

总而言之:我们首先要明白,GC的过程是需要STW(STOP-THE-WORD) 也即业务线程是需要停止工作,而GC过程中消耗大量时间回收空间,而回收后的可使用空间仅仅只有总空间的2%,往往下次new对象的时候又去GC了,周而复始,给用户的体验是当前系统已经完全卡死了~

所以在种种因素下JVM认为你已经没必要去GC了,GC也是毫无意义的事情了,完全卡死的情况下,还不如我给你抛出java.lang.OutOfMemoryError: GC overhead limit exceeded异常,开发者好好去排查一下问题~

如何解决

仅供参考,还是需要分析自身系统环境做出不同的策略。

  1. 堆空间是否设置的太少?可以在启动时添加-Xms -Xmx参数设置堆大小
  2. 分析是否存在内存泄露?
  3. 如果项目庞大,是否需要提升硬件?
  4. 启动时添加-XX:+HeapDump0n0ut0fMemoryError   -XX:HeapDumpPath= "路径" 参数下次发生OOM时便可分析
  5. 分析项目中经常使用的大对象,是否可以优化一下空间?
  6. 是否可以把项目中非重要的缓存数据设置成软、弱引用对象
  7. 以上的分析可以使用阿里开源的 "Arthas" 工具
  8. 还有很多笔者暂时没有考虑到的.......

源码论证

由于大部分的公司还是停留在Java8,并且垃圾回收器也是默认的ParallelScavenge new/old,所以直接给出ParallelScavenge new/old垃圾回收器的部分核心源码

src/share/vm/gc_interface/collectedHeap.inline.cpp 文件中, common_mem_allocate_noinit方法,此方法尝试开辟对象,如果开辟不成功,就会根据当前不同OOM异常种类Dump和抛出对应的异常

HeapWord* CollectedHeap::common_mem_allocate_noinit(KlassHandle klass, size_t size, TRAPS) {bool gc_overhead_limit_was_exceeded = false;// 尝试在堆空间开辟对象result = Universe::heap()->mem_allocate(size,&gc_overhead_limit_was_exceeded);// 根据gc_overhead_limit_was_exceeded参数区分是那种OOM异常。if (!gc_overhead_limit_was_exceeded) {// -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support// 英文注释特别明显了,如果设置了dump参数,就导出report_java_out_of_memory("Java heap space");// 抛出OOM:Java heap spaceTHROW_OOP_0(Universe::out_of_memory_error_java_heap());} else {      // -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support// 英文注释特别明显了,如果设置了dump参数,就导出report_java_out_of_memory("GC overhead limit exceeded");// 抛出OOM:GC overhead limit exceededTHROW_OOP_0(Universe::out_of_memory_error_gc_overhead_limit());}
}

而我们关心的是GC overhead limit exceeded异常,而这里是根据gc_overhead_limit_was_exceeded变量来做区分,而gc_overhead_limit_was_exceeded变量传入mem_allocate方法,所以我们接着看mem_allocate方法src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp 文件中mem_allocate方法,此方法也是开辟对象的过程。

HeapWord* ParallelScavengeHeap::mem_allocate(size_t size,bool* gc_overhead_limit_was_exceeded) {// 尝试在young_gen空间创建对象HeapWord* result = young_gen()->allocate(size);// 在年轻代没有创建出对象。while (result == NULL) {{// 因为存在锁的原因,所以下面又在年轻代尝试了一次。MutexLocker ml(Heap_lock);gc_count = Universe::heap()->total_collections();result = young_gen()->allocate(size);if (result != NULL) {return result;}// 年轻代开辟不了,老年代尝试一下。result = mem_allocate_old_gen(size);if (result != NULL) {return result;}// 超过允许尝试的次数,直接返回if (gclocker_stalled_count > GCLockerRetryAllocationCount) {return NULL;}}// 需要触发GC,回收空间后再尝试开辟对象if (result == NULL) {// 触发GC回收空间VM_ParallelGCFailedAllocation op(size, gc_count);VMThread::execute(&op);if (op.prologue_succeeded()) {// 是否达到次数,是否清空软引用了const bool limit_exceeded = size_policy()->gc_overhead_limit_exceeded();const bool softrefs_clear = collector_policy()->all_soft_refs_clear();if (limit_exceeded && softrefs_clear) {// 设置为true,代表抛出GC overhead limit exceeded异常*gc_overhead_limit_was_exceeded = true;   size_policy()->set_gc_overhead_limit_exceeded(false);return NULL;}return op.result();}}}return result;
}

我们看到后续GC回收后,判断limit_exceeded 和 softrefs_clear,如果都为true就把gc_overhead_limit_was_exceeded设置为true。

而softrefs_clear变量是清空软引用,我们知道,在JVM中,内存实在不足的时候会清空软引用

而我们看到limit_exceeded变量的设置即可。看何时把他设置为true即可。

src/share/vm/gc_implementation/share/adaptiveSizePolicy.cpp 文件中check_gc_overhead_limit方法

void AdaptiveSizePolicy::check_gc_overhead_limit(size_t young_live,size_t eden_live,size_t max_old_gen_size,size_t max_eden_size,bool   is_full_gc,GCCause::Cause gc_cause,CollectorPolicy* collector_policy) {// 当前eden空闲大小const size_t free_in_eden = max_eden_size > live_in_eden ?max_eden_size - live_in_eden : 0;// 当前老年代空闲大小const size_t free_in_old_gen = (size_t)(max_old_gen_size - avg_old_live()->average());// 当前堆空间空闲大小const size_t total_free_limit = free_in_old_gen + free_in_eden;// 堆空间的总大小const size_t total_mem = max_old_gen_size + max_eden_size;// GCHeapFreeLimit是2// 所以这里是算出比例,2%const double mem_free_limit = total_mem * (GCHeapFreeLimit/100.0);const double mem_free_old_limit = max_old_gen_size * (GCHeapFreeLimit/100.0);const double mem_free_eden_limit = max_eden_size * (GCHeapFreeLimit/100.0);// GCTimeLimit是98// 所以这里是算出比例,98%const double gc_cost_limit = GCTimeLimit/100.0;// 如果是fullgcif (is_full_gc) {// 如果GC时长超过98%// 并且回收后可用空间小于总空间的2%if (gc_cost() > gc_cost_limit &&free_in_old_gen < (size_t) mem_free_old_limit &&free_in_eden < (size_t) mem_free_eden_limit) {inc_gc_overhead_limit_count();    // 自增一次// 如果开启了次数限制if (UseGCOverheadLimit) {// 如果次数大于等于5次。if (gc_overhead_limit_count() >=AdaptiveSizePolicyGCTimeLimitThreshold){// 设置为true,到时候就会抛出GC overhead limit exceeded异常// 并且清空次数set_gc_overhead_limit_exceeded(true);   reset_gc_overhead_limit_count();} }}}// 如果设置了UseGCOverheadLimit的情况下, 不会响应此异常if (UseGCOverheadLimit && PrintGCDetails && Verbose) {if (gc_overhead_limit_exceeded()) {reset_gc_overhead_limit_count();} }
}

这里算出了堆总空间的百分之2,gc回收时间的百分之98。然后算出了GC后空闲空间的占比,GC的回收时间。最后通过比较,如果GC回收时间大于98%,并且回收后可用空间小于总空间的2% 情况下计数器+1,如果计数器达到5次就通过set_gc_overhead_limit_exceeded方法设置为true,最终抛出java.lang.OutOfMemoryError: GC overhead limit exceeded异常。

所以看了源码后,解决GC overhead limit exceeded异常,还可以通过设置

-XX:-UseGCOverheadLimit 或者 -XX:AdaptiveSizePolicyGCTimeLimitThreshold = "设置很大的数值" 都能让JVM不抛出 GC overhead limit exceeded异常。但是没任何意义,因为会一直触发GC,一直STW暂停,用户一直是卡死的状态~

相关文章:

JVM源码剖析之Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded异常

写在前面&#xff1a; 版本信息&#xff1a; jdk版本&#xff1a;jdk8u40 垃圾回收器&#xff1a;ParallelScavenge new/old最近在群里看到有一位老哥拿着异常信息到处问&#xff0c;而发生的就是java.lang.OutOfMemoryError: GC overhead limit exceeded异常&#xff0c;恰好…...

使用PDF文件入侵任何操作系统

提示&#xff1a;我们8月28号开学,所以我得快点更新了&#xff0c;不能拖了&#x1f625; 文章目录 前言一、打开终端总结 前言 PDF文件被广泛应用于共享信息&#xff0c;电子邮件&#xff0c;网站或文档或存储系统的真实链接 它可以用于恶意软件的载体。 不要问我什么意思&am…...

强训第32

选择 D B A A 发送TCP意思应该是已经建立了连接&#xff0c;会超时重传。在未建立连接的时候&#xff0c;会放弃该链接 C A 80端口是http A 交换机攻击主要有五种&#xff1a;VLAN跳跃攻击 生成树攻击 MAC表洪水攻击 ARP攻击 VTP攻击 B A 2^(32-26)2^(32-27)2^(32-27)128 减去…...

vue3 setup+Taro3 调用原生小程序自定义年月日时分多列选择器,NutUI改造

vue3 setupTaro3 调用原生小程序自定义年月日时分多列选择器&#xff0c;NutUI改造 NutUI 有日期时间选择器&#xff0c;但是滑动效果太差&#xff0c;卡顿明显。换成 原生小程序 很顺畅 上代码&#xff1a; <template><view><pickermode"multiSelector&…...

git命令使用

君子拙于不知己,而信于知己。——司马迁 清屏&#xff1a;clear 查看当前面板的路径&#xff1a;pwd 查看当前面板的文件&#xff1a;ls 创建文件夹&#xff1a;mkdir 文件夹名 创建文件&#xff1a;touch 文件名 删除文件夹&#xff1a;rm -rf 文件夹名 删除文件&#xff1a;r…...

每日记--前端解决方案--el-select下拉样式-el-option内容过长-鼠标悬停到文字不修改光标样式-设置透明

文章目录 el-select下拉样式el-select中el-option内容过长解决办法鼠标悬停到文字不修改光标样式设置透明 el-select下拉样式 element-ui自带样式设置popper-class el-select中el-option内容过长解决办法 问题&#xff1a;像这样选项太长了&#xff0c;不好看 解决&#xf…...

Windows系统Git安装教程(详细Git安装过程)

获取Git安装程序 到Git官网下载&#xff0c;网站地址&#xff1a;https://git-scm.com/downloads&#xff0c;如下图&#xff1a; 因为我们是用Windows系统上的浏览器访问的&#xff0c;Git官网自动之别到了我使用的操作系统&#xff0c;所以右侧直接显示下载使用Windows系统的…...

前后端分离------后端创建笔记(11)用户删除

B站视频&#xff1a;30-用户删除&结束语_哔哩哔哩_bilibili 1、现在我们要做一个删除的功能 1.1 首先做一个删除的功能接口&#xff0c;第一步先来到后端&#xff0c;做一个删除的接口 2、删除我们用Delete请求 3、方法名我给他改一下 3.1这里给他调一下删除方法&#xf…...

24、springboot的自动配置01--类条件注解@ConditionalOnClass、bean条件注解@ConditionalOnBean

springboot的自动配置 ★ 自动配置 Spring Boot的自动配置通常可根据依赖库自动触发——当Spring Boot检测到项目中包含某些框架的JAR包时&#xff0c;Spring Boot就会触发自动配置。其实通过EnableAutoConfiguration注解来启动▲ 其实你用到SpringBootApplication&#xff0…...

婚恋交友h5多端小程序开源版开发

婚恋交友h5多端小程序开源版开发 以下是婚恋交友H5多端小程序的功能列表&#xff1a; 用户注册和登录&#xff1a;用户可以通过手机号码或第三方账号注册和登录。个人信息填写&#xff1a;用户可以填写个人基本信息&#xff0c;包括姓名、性别、年龄、身高、体重、学历、职业等…...

uniapp案例30余种实战项目

uniapp案例30余种实战项目 mpvue框架仿滴滴出行didi-masteruni-app自定义导航栏title-customvue-mpvue-ChatRobot聊天机器人vue-mpvue-ChatRobot-master一款播课类小程序, 基于 mpvue 构建mp-podcast-mpvue-mastermpVue高仿美团小程序教程mpvue-meituan-masteruni-app 二维码生…...

回归预测 | MATLAB实现GRNN广义回归神经网络多输入多输出预测

回归预测 | MATLAB实现GRNN广义回归神经网络多输入多输出预测 目录 回归预测 | MATLAB实现GRNN广义回归神经网络多输入多输出预测预测效果基本介绍程序设计往期精彩参考资料 预测效果 基本介绍 MATLAB实现GRNN广义回归神经网络多输入多输出预测&#xff0c;输入10个特征&#x…...

从零开始学习VBA(一)

前置配置设置 首先配置开发设置&#xff08;不同版本的配置方法会有差异&#xff0c;可根据自己使用的EXCEL版本到网络上找对应的方法&#xff0c;比如直接搜索Excel2010 开发工具&#xff09; 以下为excel2016配置方法&#xff1a; 操作路径&#xff1a;文件-选项-自定义功…...

Kotlin Executors线程池newSingleThreadExecutor单线程

Kotlin Executors线程池newSingleThreadExecutor单线程 import java.util.concurrent.Executorsfun main() {val mExecutorService Executors.newSingleThreadExecutor()for (i in 1..5) {mExecutorService.execute {println("seq-$i tid:${Thread.currentThread().threa…...

ZooKeeper介绍

ZooKeeper是一个开放源代码的分布式协调服务。ZooKeeper的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来&#xff0c;构成一个高效可靠的原语集&#xff0c;并以一系列简单易用的接口提供给用户使用。 ZooKeeper是一个典型的分布式数据一致性的解决方案&#xff0…...

首起针对国内金融企业的开源组件投毒攻击事件

简述 2023年8月9日&#xff0c;墨菲监控到用户名为 snugglejack_org (邮件地址&#xff1a;SnuggleBearrxxhotmail.com&#xff09;的用户发布到 NPM 仓库中的 ws-paso-jssdk 组件包具有发向 https://ql.rustdesk[.]net 的可疑流量&#xff0c;经过确认该组件包携带远控脚本&a…...

源于传承,擎领未来,新架构、新工艺下的“换心工程”——金融电子化访中电金信副总经理、研究院院长况文川

当前&#xff0c;商业银行的经营环境正在发生着深刻而复杂的变化&#xff0c;在深化改革主旋律的指引下&#xff0c;数字化转型已成为我国商业银行普遍认同、广泛采用的战略性举措。核心系统作为承载银行业务的关键支柱系统&#xff0c;一直是各银行在金融科技建设中重点关注和…...

pytest数据驱动(最简单)

目录 第一种&#xff1a;通过yaml文件获取数据&#xff08;一维列表&#xff09; 第二种&#xff1a;通过yaml文件获取数据&#xff08;二维列表&#xff09; 第三种&#xff1a;通过yaml文件获取数据&#xff08;pytest.fixture&#xff09; 资料获取方法 第一种&#xff…...

分布式 - 服务器Nginx:一小时入门系列之代理缓冲与缓存

官方文档&#xff1a;https://nginx.org/en/docs/http/ngx_http_proxy_module.html 1. 代理缓冲 proxy_buffer 代理缓冲用于临时存储从后端服务器返回的响应数据。通过使用代理缓冲&#xff0c;Nginx可以在接收完整的响应后再将其发送给客户端&#xff0c;从而提高性能和效率…...

什么是集成学习算法

目录 什么是集成学习算法 集成学习发展史 集成学习组织方式 1) 并联组织关系...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

PAN/FPN

import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

【堆垛策略】设计方法

堆垛策略的设计是积木堆叠系统的核心&#xff0c;直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法&#xff0c;涵盖基础规则、优化算法和容错机制&#xff1a; 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则&#xff1a; 大尺寸/重量积木在下&#xf…...

保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!

目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...

鸿蒙(HarmonyOS5)实现跳一跳小游戏

下面我将介绍如何使用鸿蒙的ArkUI框架&#xff0c;实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...

基于鸿蒙(HarmonyOS5)的打车小程序

1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...

Java 与 MySQL 性能优化:MySQL 慢 SQL 诊断与分析方法详解

文章目录 一、开启慢查询日志&#xff0c;定位耗时SQL1.1 查看慢查询日志是否开启1.2 临时开启慢查询日志1.3 永久开启慢查询日志1.4 分析慢查询日志 二、使用EXPLAIN分析SQL执行计划2.1 EXPLAIN的基本使用2.2 EXPLAIN分析案例2.3 根据EXPLAIN结果优化SQL 三、使用SHOW PROFILE…...

C++--string的模拟实现

一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现&#xff0c;其目的是加强对string的底层了解&#xff0c;以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量&#xff0c;…...