意想不到,这个神奇的bug让我加班到深夜
给大家分享一个近期解决的线上问题,起因是这样的,近期参与公司的一个项目,工程量很大,代码编写测试过后终于到了紧张的上线时刻。
项目上线
上线前照例忐忑不安了一番,因为工程量比较大,预估可能不会很顺利,但还不至于到了祈祷服务器不要出bug的地步,bug对于程序员来说简直是家常便饭,没有bug反而可能会嘀咕半天,这都是职业病,没治。
紧张了一会儿,我屏气凝神,点了上线按钮,那一刻简直就像在点核按钮一样,生怕点下去后服务器会轰的一声炸掉。

结果一切正常。。。
这不对啊,这时博主的职业病又犯了,这么大的改动不会这么顺利吧,内存、CPU、tp99耗时一切正常,这太不正常了吧。
说曹操曹操就到
就在博主想为什么没有bug时,bug简直就像听到了我的召唤一样如约而至,博主当时甚至在想为什么梦想中的500万彩票就这么不听话呢?
(bug妹妹:“程序员哥哥,我来啦”;
500万妹妹:“不,程序员哥哥,不要说门,窗户都没有。。。”)
上线最初一切正常,问题就出在了接下来的一段时间里。
在接下来的时间里,tp99耗时就像通货膨胀一样不可遏制的一路上扬,线上收入就像股市一样不可遏制的一路重挫。

这时博主的内心反而踏实了很多,没错,就是这个味儿,还是熟悉的配方还是熟悉的味道,I know it。
废话少说,赶紧回滚,线上恢复正常后接下来就是问题排查了。
排查问题
从监控上看,一次请求的处理时间会越来越高,那么显然问题的关键就是定位耗时出现在了哪段代码上。
没有办法,只能一点一点的去找监控了,幸好代码中监控比较丰富,一番梳理后最终锁定在了这样一行代码:
// 监控代码
obj a = b;
// 监控代码
这段代码本质上是在干什么呢?很简单,就是对象的copy,而且在我们的实现中还是浅copy,也就是仅仅copy了一些字段。
从监控看就是这行代码导致了tp99耗时不断上涨。
这。。这怎么可能呢?简简单单的一个对象拷贝竟然会让耗时上涨那么多,而且还是随着时间缓慢上涨,这也太神奇了吧。

当人遇到自己不能理解的问题时通常会归因于外部因素,博主也不能免俗。
接下来就是怀疑人生的时刻。
不会是监控有问题吧,不会是编译器的原因吧,不会是硬件的原因吧,不会是天气的原因的吧,总之不是我的原因。

一番思索后最终理性战胜了自己,哪有那么多原因,在没有其它证据下目前看就是这个对象拷贝导致的。
那么为什么一个简单的对象拷贝会导致CPU消耗越来越高,耗时越涨越多呢?
这里的关键在于意识到这一点,既然随着时间的推移耗时会越来越高,那么很显然是某个全局性质的数据随着请求的处理越堆积越多,而出问题的这个对象使用到了这个全局数据。没错,就是这样,终于要见到曙光啦,哈哈,激动!

这就解释了为什么这个对象随着时间的推移就和美债一样越滚越多,变得越来越庞大了,虽然美国政府可能没打算还美债,但是CPU拷贝越来越多的数据必然导致耗时越来越高。
找出bug
既然明确了方向,接下来就有针对性了。
首先去看一下这个对象都有哪些成员变量,对于内置类型像int、bool之类肯定不会有问题,因为这些类型的变量大小是固定的,需要注意的就是这种vector、set之类的容器。
最终经过一番检查后断定问题就是出在了某个vector成员变量上,同时也验证了上述猜想。
真相大白
问题是这样的。
这个对象的某个vector成员变量每次在处理请求时都要用另一个对象(假设为对象A)的数据来进行初始化,就像这样:

在每次处理一个请求之前,A持有的Data都会被push一些特定的数据。
而系统为了优化内存分配开销,对象A被放到了内存池中,就像这样:

由于对象被放到了内存池,因此对象A是不会被释放的,这就让对象A无形中变为了全局性质的对象。
现在,有的同学可能已经发现问题了,那就是,如果对象A在放回内存池后没有清空持有的Data,那么就会导致这样的一个问题,那就是A持有的Data随着每个请求的到来不断的被push数据,这就会导致A持有的Data就像泡沫一样越吹越大,相应的Obj对象持有的vector也会越来越大:

在这种情况下拷贝Obj对象必然要拷贝持有的vector,由于vector越来越大,因此消耗在拷贝上的时间也越来越多,使用内存池本意是好的,但由于使用完后忘记清理其保存的旧数据反而造成了内存泄漏。
经验教训
这次的问题从代码编写角度看是这样的,对象A中Data字段的清理工作没有放在对象A的Clear函数,反而要靠使用者自己清理,由于代码非常复杂极其容易疏漏,博主就在这里踩坑了。。。
因此,总结下来经验教训就是:
- 向类中添加新成员时一定要注意其清理工作,使用前一定要确保该成员是崭新的,里面没有之前旧存货。
- 代码中添加必要的监控,有利于排查问题
- 测试的时间要稍微长一些,否则类似这里的问题不容易暴露
- 程序员遇到bug是很正常的,大胆假设,小心求证,每次问题的解决都是能力的提升
查到问题后,修bug、自测、验证、代码提交一气呵成,再次上线就明天了,收工回家。
从下午上线发现问题到问题解决耗时超过6小时,博主到家时,已是满天繁星。
希望本文能帮助大家避开一些坑。
意想不到,这个神奇的bug让我加班到深夜的更多相关文章
- 神奇的bug,退出时自动更新时间
遇到一个神奇的bug,用户退出时,上次登录时间会变成退出时的时间. 于是开始跟踪,发现Laravel在退出时,会做一次脏检查,这时会更新rember_token,这时就会有update操作如下. 而粗 ...
- 一个神奇的bug:OOM?优雅终止线程?系统内存占用较高?
摘要:该项目是DAYU平台的数据开发(DLF),数据开发中一个重要的功能就是ETL(数据清洗).ETL由源端到目的端,中间的业务逻辑一般由用户自己编写的SQL模板实现,velocity是其中涉及的一种 ...
- 记一个神奇的Bug
多年以后,当Abraham凝视着一行行新时代的代码在屏幕上川流不息的时候,他会想起2019年4月17日那个不平凡夜晚,以及在那个夜晚他发现的那个不可思议的Bug. 虽然像无数个普普通通的夜晚一样,我在 ...
- 我是这样搞懂一个神奇的BUG
摘要: 通过分析用户的行为,才想得到为什么会出现这种情况! 前两天在BearyChat收到这样的一个报警消息: 409 ?Conflict ? 平时很少遇到这样的错误,貌似很严重的样子,吓得我赶紧查看 ...
- 神奇的BUG系列-01
有时候遇见一个bug,感觉就是他了 其实他也不过是你职业生涯中写的千千万万个bug中的一员 你所要做的,是放下 日子还长,bug很多,不差这一个 就此别过,分手快乐 一辈子那么长,一天没放下键盘 你就 ...
- jquery on 动态添加的元素,神奇的bug
$(document.body).on("click", ".comments-item .link-comment", function () { 平时用 d ...
- 一个神奇的bug
在使用touch命令创建了一个swift文件后,如果用xcode打开该文件,然后输入 #!/usr/bin/env xcrun swift 接着你就会发现,xcode崩溃了.
- 一个神奇的BUG :Failed to finalize session : INSTALL_FAILED_INVALID_APK: /data/app/vmdl99393454.tmp/10_slice__ signatures are inconsistent
Android Studio 在Gradle编译完成后安装APK时总是失败,EventLog提示如下信息: Failed to finalize session : INSTALL_FAILED_IN ...
- a标签点击跳转失效--IE6、7的奇葩bug
一般运用a标签包含img去实现点击图片跳转的功能,这是前端经常要用到的东西. 今天遇到个神奇的bug:如果在img上再包裹一层div,而且div设置了width和height,则图片区域点击时,无任何 ...
随机推荐
- 剑指offer二刷——数组专题——数组中重复的数字
题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为 ...
- 题解 P5401 [CTS2019]珍珠
蒟蒻语 这题太玄学了,蒟蒻写篇题解来让之后复习 = = 蒟蒻解 假设第 \(i\) 个颜色有 \(cnt_i\) 个珍珠. \(\sum\limits_{i=1}^{n} \left\lfloor\f ...
- NameSilo的DDNS动态域名解析
用Java写的,一个实时检测IP变化并更新DNS状态的工具,适用于在NameSilo购买的域名,如果你的域名是在其他商家购买的,修改为你自己的api就行.代码我放github了,地址: https:/ ...
- Java-静态关键字Static&静态代码块
静态成员变量:(static修饰变量) 如果一个成员变量使用了static关键字,那么这个变量不再属于对象自己,而是属于所在的类.多个对象共享同一份数据. 静态方法:(static修饰方法) 一旦使用 ...
- latex参考文献删除[.s.l],[.s.n]
用latex写毕业论文的插入会议参考论文的时候可能会遇到编译后的文档里面一堆[.s.l],[.s.n]的问题. 这是因为ref里面会议条目找不到地址信息,所以用[.s.l],[.s.n]替代,只需要更 ...
- jmeter__编写脚本学习笔记、备忘
web持续添加 前言: 1. token就是令牌,比如你授权(登录)一个程序时,他就是个依据,判断你是否已经授权该软件:也叫关联 2. cookie就是写在客户端的一个txt文件,里面包括你登录信息之 ...
- Kudu的特点
Kudu的特点 0.原理 列式存储管理器 一个列式存储数据的地方,跟mysql差不多,只是mysql是行式存储. 他是一个集群,能分布式存储. 查询也是写sql语句. 列式存储效率高. 1.为什么会有 ...
- [BUUCTF] 真的很杂
这似乎是一道安卓逆向题??我就是没有搞懂安卓逆向原来是misc吗... 安卓逆向一个例子 工具准备 1.apktool--可以反编译软件的布局文件.图片等资源,方便大家学习一些很好的布局: 2.dex ...
- Python将word文档转换成PDF文件
如题. 代码: ''' #將word文档转换为pdf文件 #用到的库是pywin32 #思路上是调用了windows和office功能 ''' #导入所需库 from win32com.client ...
- easyui中开始时间小于结束时间 不然无法点击
<tr> <td align="right">用药开始时间:</td> <td><input id="time_fr ...