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

线上报了内存溢出异常,又不完全是内存溢出

(一)前言

最近一直忙于对付即将上线的系统,期间也碰到了很多问题。最近印象比较深的是一个内存溢出的报错。测试告诉我最近某个功能总是没有效果,于是我就去线上看了一下错误日志,这不看不知道,一看吓一跳,满屏的OutOfMemoryError ,出于隐私保护,这里只展示其中的一点异常信息:

(二)思考场景

一般查问题首先是看日志,然后是思考场景,为什么在这个场景下会发生内存溢出的异常。于是我就思考了一下这段代码的逻辑,这里是一个异步线程的数据提取功能:通过dubbo接口,每次调用1000条数据,再对这些数据做一些处理后落入库,数据的总量在几万至几十万不等。

这里如果会出现内存溢出,唯一有可能的是每次调用的1000条数据在数据处理后没有清空,导致几十万数据都加入进内存中,最后内存溢出。于是去检查了这部分的代码:

List<EmrTreatment> resultList = new ArrayList<>();
//如果数据还有,则不跳出循环
while (CollectionUtils.isNotEmpty(data.getRecords())) {
    resultList.addAll(dataPage.getRecords());
    //业务处理
    //.......
    //清空集合防止内存溢出
    resultList.clear();
    // 通过dubbo接口请求接下来的1000条
    //... ...
   data=searchDataByScroll(dataRequest);  
}

我特意在1000条处理完成后清空了List,就不存在内存溢出的情况。

(三)查看GC日志

因为是堆内存溢出,于是立刻想到了去看看GC日志,但是一点内存溢出的意思也没有,顺便重温一下GC日志的内容表示的含义:

以其中的单条为例:

GC (Allocation Failure) 2021-10-29T16:37:45.177+0900: 2686.339  [ParNew: 283195K->3579K(314560K), 0.0256691 secs] 396015K->116915K(1013632K), 0.0258253 secs] [Times: user=0.03 sys=0.02, real=0.03 secs]

GC: 表明进行了一次垃圾回收,属于MinorGC

Allocation Failure:GC发生原因是因为年轻代空间不足

ParNew:本次GC年轻代使用的是ParNew垃圾收集器

283195K->3579K(314560K):GC前年轻代使用量->GC后年轻代使用量(年轻代总容量)

396015K->116915K(1013632K):堆区垃圾回收前使用量->堆区垃圾回收后使用量(堆大小)

[Times: user=0.04 sys=0.00, real=0.01 secs]:

user:垃圾收集线程消耗的所有CPU时间

sys:系统等待时间

real:应用暂停总时间(STW)

既然GC日志中没有堆内存溢出的信息,说明不是我们应用的内存溢出,又仔细看了一下报错信息,有很明显的错误指向dubbo,说明之前的路走歪了。

(四)检查dubbo接口配置

依稀记得dubbo接口调用时设置了每次的调用大小,于是上nacos检查配置,果然dubbo接口设置了16M的大小,这一下就定位到问题了。每次从dubbo接口取1000条数据在某些数据量比较大的情况下超过了16M,返回了一个OutOfMemory Error。

(五)解决方案

既然定位到了问题,解决方案也就简单了,首先根据实际情况调整dubbo接口的消费者和生产者限制大小,其次将每次调用1000次修改略微小一点。再者按照原来的设计1000条数据是不会超过16M的,于是检查了数据,发现有的数据单条就超过了2M,这类数据的使用价值不大,因此在产品上考虑是否过滤掉这些数据。最终上线验证没有再报同样的问题,算是解决了。

(六)总结

虽然问题是解决了,但是还是走了一些歪路。碰到紧急问题时脑子不会像事后那么清晰,但是踩的坑越多,学到的也就越多。

相关文章:

  • 用代码告诉你“问世间情为何物,直教人生死相许”
  • 互联网公司的完整开发流程是怎样的?
  • 如何在SpringBoot启动时执行初始化操作,两个简单接口就可以实现
  • BZOJ4584 : [Apio2016]赛艇
  • 查准考证网站卡了整整一个小时进不去,被抢票支配的恐惧又来了
  • 【C#公共帮助类】 ToolsHelper帮助类
  • 这次终于把Spring的监听器讲明白了
  • jquery ajax分页 js对象
  • 详解单例模式及其在Sping中的最优实践
  • Magento Shell
  • 深入了解ElasticSearch的Nested数据类型
  • Python3发送post请求,自动记住cookie
  • 基于SpringCloudGateway实现微服务网关
  • .NET框架
  • MongoDB快速上手,聊聊这款火了一阵又销声匿迹的非关系型数据库
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • 【React系列】如何构建React应用程序
  • 11111111
  • android百种动画侧滑库、步骤视图、TextView效果、社交、搜房、K线图等源码
  • GitUp, 你不可错过的秀外慧中的git工具
  • hadoop集群管理系统搭建规划说明
  • js算法-归并排序(merge_sort)
  • JWT究竟是什么呢?
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • linux学习笔记
  • node和express搭建代理服务器(源码)
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • Python语法速览与机器学习开发环境搭建
  • Shell编程
  • socket.io+express实现聊天室的思考(三)
  • spring学习第二天
  • Webpack 4 学习01(基础配置)
  • 初识MongoDB分片
  • 给新手的新浪微博 SDK 集成教程【一】
  • 构建工具 - 收藏集 - 掘金
  • ​LeetCode解法汇总1410. HTML 实体解析器
  • ​力扣解法汇总946-验证栈序列
  • #Lua:Lua调用C++生成的DLL库
  • #pragma pack(1)
  • #宝哥教你#查看jquery绑定的事件函数
  • %@ page import=%的用法
  • (11)工业界推荐系统-小红书推荐场景及内部实践【粗排三塔模型】
  • (13)[Xamarin.Android] 不同分辨率下的图片使用概论
  • (13)Hive调优——动态分区导致的小文件问题
  • (python)数据结构---字典
  • (保姆级教程)Mysql中索引、触发器、存储过程、存储函数的概念、作用,以及如何使用索引、存储过程,代码操作演示
  • (大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量
  • (动手学习深度学习)第13章 计算机视觉---图像增广与微调
  • (紀錄)[ASP.NET MVC][jQuery]-2 純手工打造屬於自己的 jQuery GridView (含完整程式碼下載)...
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (轉貼) 寄發紅帖基本原則(教育部禮儀司頒布) (雜項)
  • *上位机的定义
  • .NET Core 和 .NET Framework 中的 MEF2
  • .NET 线程 Thread 进程 Process、线程池 pool、Invoke、begininvoke、异步回调
  • .net(C#)中String.Format如何使用