BSS段内存问题排查笔记

Author Avatar
Kanglai Qian 4月 03, 2023

本周版本的时候QA同学跑过来说iPhone 13进游戏闪退,而且没有抓到闪退的堆栈信息; 盲猜是内存问题,当时手头在忙就直接找人试了下低端一些的设备,结果没有翻车orz 就一时间有点摸不到头脑。
后来腾出手直接XCode连着看了下,雀实是内存冲到2G之后被系统干了,在- (void)applicationDidReceiveMemoryWarning:(UIApplication*)application里打了行LOG也触发到了。

昨天在家终于有空仔细研究下这个问题,最后发现还是蛮少见的情况… 特意记录一下笔记。

首先重新描述下问题: ios真机上打开登录界面就内存占用达到1G,登录加载场景后会飙升到1.8G然后被系统干掉;翻了下QA同学的历史包数据,登录进游戏跑测之后也应该维持在1G上下。

掏出祖传instruments,查了下进登录界面的allocation情况发现一切正常,而且也就100M不到的情况(这里反而是发现有个SDK在频繁申请、释放一块128M内存需要跟进下emmm)。
这时候楚东发现了一个诡异的地方,_DATA字段有个超大的分配需要关注。

由于对XCode相关功能不太熟悉,我索性换到PC平台来查这个问题: 先掏出VMMap看下登录界面的内存情况,发现Heap部分只有75M左右,大头反而是Image部分的.data段——说明被下毒的地方是.data里面!

接下来试图继续排查这个dll里的.data里有啥。一开始是熟练的启动了IDA,结果加载PDB的时候非常卡——处理debug symbols耗费差不多半小时,而且随便jump address就卡哭。

索性换个思路,研究下有没有别的方法可以导出.data段的内容: 毕竟是我本地编译的dll+pdb,所有信息其实都是全的。在等IDA的时候,从M$文档里翻到了/MAP (Generate Mapfile),试着生成了下果然定位到同样的问题:.bss字段的长度过于鹤立鸡群了…

Timestamp is 64283074 (Sat Apr  1 21:24:04 2023)

Preferred load address is 0000000180000000

Start Length Name Class
0003:00000000 001a9a90H .data DATA
0003:001a9a90 000975c0H .data$r DATA
0003:00241050 0017fcb0H .data$rs DATA
0003:003c0d00 39376098H .bss DATA
0004:00000000 00278a6cH .pdata DATA

然后下面有具体的列表,索性在sublime里排序之后,肉眼跳着看找到了地址跳变的两条记录

0003:006cf170       ?sHPFM@MMM@@3VHPFManager@HP@1@A 000000018556a170     AAA.obj
0003:37ee4b78 ?thousand_separator_locale@MMM@@3Vlocale@std@@A 00000001bcd7fb78 AAA.obj

对着这条记录去翻对应的C++实现,然后暴力编译输出了一发大小:

static HP::HPFManager sHPFM;
char(*test)[sizeof(HP::HPFManager)] = 1;

结论就是这个manager占用了931M的内存…

AAA.cpp(31,56): error C2440: 'initializing': cannot convert from 'int' to 'char (*)[931224072]'
AAA.cpp(31,56): error C2440: char(*test)[sizeof(HP::HPFManager)] = 1;
AAA.cpp(31,56): error C2440:

至此问题就比较清晰了,是因为这个Manager类实现的不合理导致的~ 回头准备再写个Python脚本分析下.data段其它变量占用情况,有没有不合理的。

说实话这个问题有趣之处在于内存占用出现在.bss而不是heap上,导致习惯性查new/malloc的手段就完全定位不到问题。奇怪的经验又增加了呢orz