【翻车记录】记OutOfMemory异常:GC overhead limit exceeded

问题起源:

项目需要一个统计数量的功能,我在实现这个功能的时候为了代码的结构,在Service中每一个方法都会进行SQL查询,并且count,然而上线后,突然出现了一个问题,CPU占用100%,服务卡住不动了。

这是为啥呢,本地运行是没有问题的。突然想到之前看过服务器如果访问的人数过多,就会导致并发问题。于是我准备在本地进行压力测试。

压力测试工具

这里采用的是WebBench,由于工作环境是mac系统,所以要用命令行操作。

brew install wget # 安装wget,这个是可以从web下载资源的东西
brew install ctags # 依赖安装,是webBench的依赖
wget http://blog.zyan.cc/soft/linux/webbench/webbench-1.5.tar.gz # 下载webBench
tar -zxvf webbench-1.5.tar.gz # 解压文件
cd webbench-1.5 
mkdir -pv /usr/local/man/man1 # 必须
sudo make && sudo make install # sudo 权限因为需要创建文件夹

到此为止,webBench就装好了,以上参考了其他博客。

然后关闭nginx,启动springBoot,准备进行测试。

nginx -s stop  # 关闭nginx
webbench -c 400 --get http://localhost:8080/api/count  # 发送400个并发GET

伴随着大量Full GC,OutOfMemory出现了。

原因

GC overhead limit exceeded

这是一个很极端的情况,内存几乎满了,而GC对他毫无办法,没有对象可以被回收从而得到充足的内存,一般来说,当耗费在GC上面的时间超过一定程度,而回收率非常低的时候会出现,我的代码中有很多不停的查询数据库的操作,这些操作是借助于Hibernate进行而不是原始SQL,每一个方法内部也会有一些对象来临时存放查询结果。

由于Hibernate懒加载,在对得到的对象进行遍历和转换(java8 Stream流的使用)的时候,懒加载的关系字段就会从数据库读取新的数据,懒加载嘛,什么时候用什么时候读,但是问题就来了,读取数据库是很费时间的,一堆用了懒加载的东西,然后一个一个的从数据库读取他们关联的数据,或许一个两个看不出影响,但是1k个对象的懒加载,他们消耗的时间就会是无法承受的了。

无法承受的原因,就是因为内存是有限的,而web是并发的,上一个还没处理好,新的请求就来了,而一个请求处理的时间又长,这样,数据就会堆积在内存,如果并发的数量很多,那么大量堆积在内存的数据,就会导致OutOfMemory

解决

整合所有需要查询的方法,合并相同或相似的查询,用stream方法代替查询中的各种条件,以减少中间变量的出现以及查询次数。

操作一通之后,OOM就没了,可以轻松承受之前的并发数。

在刚刚开始修改的时候,我并没有发现有很多的冗余代码可以简化掉,在这些操作中,有一个很耗时的SQL,单独执行的话无非是慢一点,但是一旦在并发环境下,这就会导致很多在此方法中进行耗时操作的对象的堆积,这些对象还正在被使用,因此GC无法回收他们,也无法得到更多内存,所以就会出现这个问题。

因此,以后的代码中,如果能够通过一个查询就可以解决的,绝对不用多个,避免非常费时间的各类操作(像是SQL什么的)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]:在Java编程中,当出现"java.lang.OutOfMemoryError: GC overhead limit exceeded"错误时,意味着Java虚拟机(JVM)花费了太多的时间在垃圾回收上,但回收的内存却非常有限。这个错误通常是由于堆内存设置过小导致的。\[3\]当垃圾回收占用了超过98%的时间,并且回收的堆内存不到2%时,就会抛出这个异常。这种情况下,JVM会认为垃圾回收的效果不好,进而抛出异常。引用\[2\]中提到了解决这个问题的方法。一种解决方法是增加JVM的堆内存大小,可以通过修改JVM的启动参数来实现。另一种解决方法是检查代码中是否存在内存泄漏或者过度使用内存的情况,例如循环引用、大量的对象创建等。通过优化代码,可以减少内存的占用,从而避免这个错误的发生。所以,当出现"java.lang.OutOfMemoryError: GC overhead limit exceeded"错误时,可以考虑增加堆内存大小或者优化代码来解决这个问题。 #### 引用[.reference_title] - *1* *3* [java.lang.OutOfMemoryError: GC overhead limit exceeded问题分析及解决](https://blog.csdn.net/whc888666/article/details/128496598)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Java IDEA pom 报错java.lang.OutOfMemoryError: GC overhead limit exceeded 基本所有依赖都报错(除了JDK...](https://blog.csdn.net/weixin_45268865/article/details/123839339)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值