微信团队原创分享:iOS版微信的内存监控系统技术实践

  • 时间:
  • 浏览:2
  • 来源:5分排列3APP下载_5分排列3APP官方

4)互相引用:

《微信团队分享:微信每日亿次实时音视频聊天转过身的技术解密》

3)最后插入Stack3,G、F、E、D结点hash命中;但可能Stack3的A的上原来地址D索引是4,而都有已有的(A, 5),hash不命中,查找下原来空白位置8,插入结点(A, 4);B上原来地址A索引是8,而都有已有的(B, 5),hash不命中,查找下原来空白位置9,插入结点(B, 9)。Stack3索引入口是9。

《全面总结iOS版微信升级iOS9遇到的各种“坑”》 

《微信团队原创分享:Android版微信的臃肿之困与模块化实践之路》

1)监控粒度过低细,像少量分配小内存引起的质变无法监控,另外fishhook不到hook自身app的C接口调用,对系统库不起作用;

举个例子,以往图片缩放接口是原来 写的:

《移动端IM实践:iOS版微信小视频功能技术方案实录》 

2)打log间隔不好控制,间隔过长可能丢失中间峰值清况 ,间隔过短会引起耗电、io频繁等性能什么的问题;

接着对可疑的Category计算型态值,也要是 OOM原应。型态值是由“Caller1”、“Caller2”和“Category, Reason”组成。Caller1是指申请内存点,Caller2是指具体场景或业务,它们都有从Category下分配大小第一的堆栈提取。Caller1提取尽量是有意义的,不有之前 分配函数的上一地址。同类:

《QQ 18年:解密8亿月活的QQ后台服务接口隔离技术》

微信自15年年底上线FOOM上报,从最初数据来看,每天FOOM次数与登录用户数比例接近3%,同期crash率1%不到。而16年年初某东老大反馈微信频繁闪退,在艰难拉取2G十天志后,才发现kv上报频繁打log引起FOOM。接着16年8月不少内部用户反馈微信启动不久后闪退,分析少量日志还是不到找到FOOM原应。微信急需原来有效的内存监控工具来发现什么的问题。

首先把所有对象按Category进行归类,统计每个Category的对象数和分配内存大小。这列表数据很少,还不能做全量上报。接着对Category下所有相同堆栈做合并,计算每项堆栈的对象数和内存大小。对于太满Category,如分配大小TOP N,可能UI相关的(如UIViewController、UIView同类的),它中间分配大小TOP M的堆栈才做上报。上报格式同类原来 :

《腾讯技术分享:社交网络图片的速率单位压缩技术演进之路》

不过这方案有不少缺点:

1)Stack1的G、F、E、D、C、A、依次插入到Hash Table,索引1~6结点数据依次是(G, 0)、(F, 1)、(E, 2)、(D, 3)、(C, 4)、(A, 5)。Stack1索引入口是6;

《腾讯原创分享(二):怎么才能 才能 大幅压缩移动网络下APP的流量消耗(上篇)》 

《腾讯团队分享:手机QQ中的人脸识别酷炫动画效果实现详解》

《企业微信客户端中组织架构数据的同步更新方案优化实战》

《一篇文章get微信开源移动端数据库组件WCDB的一切!》

1)先回顾Facebook怎么才能 才能 判定上一次启动有无经常老出FOOM:

《首次揭秘:QQ实时视频聊天转过身的神秘组织》

《开发岁月电视剧:宽度讲述2010到2015,微信一路风雨的转过身》 

《微信团队原创分享:iOS版微信的内存监控系统技术实践》

《微信团队披露:微信界面卡死超级bug“15。。。。”的来龙去脉》

《移动端IM实践:iOS版微信界面卡顿监测方案》 

《QQ音乐团队分享:Android中的图片压缩技术详解(下篇)》

太满二期版本以Instruments的Allocations为参考,着重三个白方面优化,分别是数据采集、存储、上报及展现。

FOOM(Foreground Out Of Memory),是指App在前台因消耗内存太满引起系统强杀。对用户而言,表现跟crash一样。Facebook早在2015年8月提出FOOM检测办法,大致原理是排除各种清况 后,剩余的清况 是FOOM,具体链接:https://code.facebook.com/posts/11469300688654547/reducing-fooms-in-the-facebook-ios-app/。

《微信团队原创分享:微信客户端SQLite数据库损坏修复实践》 

另外为了更好的归类数据,每个内存对象应该有它所属的分类Category,如上图所示。对于堆内存对象,它的Category名是“Malloc ”+分配大小,如“Malloc 48.00KiB”;对于虚拟内存对象,调用vm_allocate创建时,最后的参数flags代表它是哪类虚拟内存,而并都有flags正对应于上述函数指针__syscall_logger的第原来参数type,每个flag具体含义还不能在头文件找到;对于OC对象,它的Category名是OC类名,当当让我们 还不能通过hook OC办法+[NSObject alloc]来获取:

经过上述优化,内存监控工具在苹果6手机手机4 6Plus运行占用CPU占用率13%不到,当然这是跟数据量有关,重度用户(如群太满、消息频繁等)可能占用率稍微偏高。而存储数据内存占用量20M左右,都用mmap办法把文件映射到内存。有关mmap好处可自行google之。

经过原来 的后缀压缩存储,平均栈长由原来 的35缩短到5不到。而每个结点存储长度为64bits(36bits存储地址,28bits储存parent索引),hashTable空间利用率300%+,原来堆栈平均存储长度只时要66.7bytes,压缩率高达42%。

《快速裂变:见证微信强大后台架构从0到1的演进历程(二)》 

a) App那么升级;

比较容易经常老出互相引用的地方是block里使用了self,而self又持有并都有block,不到通过代码规范来出理 。另外NSTimer的target、CAAnimation的delegate,是对Obj强引用。目前微信通过买车人实现的MMNoRetainTimer和MMDelegateCenter来规避同类什么的问题。

《微信团队原创分享:Android版微信从3000KB到300MB的技术演进》 

《开发岁月电视剧:记录微信3.0版转过身的故事(距微信1.0发布9个月时)》 

《微信“红包照片”转过身的技术什么的问题》 

《Android版微信从3000KB到300MB的技术演进(PPT讲稿) [附件下载]》 

《移动端IM实践:Android版微信怎么才能 才能 大幅提升交互性能(一)》

为此,还不能用Hash Table来存储哪几种堆栈。思路是整个堆栈以链表的办法插入到table里,链表结点存放当前地址和上原来地址所在table的索引。每插入原来地址,先计算它的hash值,作为在table的索引,可能索引对应的slot那么存储数据,就记录并都有链表结点;可能有存储数据,有之前 数据跟链表结点一致,hash命中,继续出理 下原来地址;数据不一致,原应hash冲突,时要重新计算hash值,直到满足存储条件。举个例子(错综复杂了hash计算):

● 其它Category分配大小有无异常,对象个数有无异常

3)上报的原始log靠人工分析,缺少好的页面工具展现和归类什么的问题。

页面展现参考了Allocations,可看出有哪几种Category,每个Category分配大小和对象数,太满Category还能看分配堆栈。

《iOS后台唤醒实战:微信收款到账语音提醒技术总结》

《快速裂变:见证微信强大后台架构从0到1的演进历程(一)》

● Memory Usage Performance Guidelines

APP在运行期间会少量申请/释放内存。以上图为例,微信启动10秒内,可能创建了3000万对象,释放了3000万,性能什么的问题是个挑战。另外在存储过程中,也尽量减少内存申请/释放。太满放弃了sqlite,改用了更轻量级的平衡二叉树来存储。

5)前台卡死引起系统watchdog强杀:

[1] QQ、微信团队原创技术文章:

1)UIGraphicsEndImageContext:

每项系统会在后台短暂唤起app,ApplicationState是Active,但又都有BackgroundFetch;执行完didFinishLaunchingWithOptions就退出了,都有收到BecomeActive通知,但太快也退出;整个启动过程持续5~8秒不等。出理 办法是收到BecomeActive通知一秒后,才认为这次启动是正常的前台启动。这办法不到减少误判概率,太满能彻底出理 。

《微信团队原创分享:Android内存泄漏监控和优化技巧总结》 

(本文同步发布于:http://www.52im.net/thread-1422-1-1.html)

《微信团队分享:微信Android版小视频编码填过的哪几种坑》 

● UIImage数量有无异常

《怎么才能 才能 解读《微信技术总监谈架构:微信之道——大道至简》》

微信原来 在17年5月底爆发少量GIF crash,该crash由内存越界引起,但收到crash信号写crashlog时,可能内存池损坏,组件无法正常写crashlog,甚至引起二次crash;上层也无法收到crash通知,有之前 误判为FOOM。目前改成不依赖crash回调,有之前 本地指在上一次crashlog(不管有无完正),就认为是crash引起的APP重启。

《移动端IM实践:WhatsApp、Line、微信的心跳策略分析》 

二级分类:

《开发岁月电视剧:微信千年不变的那张闪屏图片的由来》 

《微信技术总监谈架构:微信之道——大道至简(演讲全文)》

b) App那么调用exit()或abort()退出;

《技术岁月电视剧:创业初期的腾讯——16年前的冬天,谁动了马化腾的代码》 

f) App当时那么后台运行;

https://developer.apple.com/library/content/documentation/Performance/Conceptual/ManagingMemory/ManagingMemory.html#//apple_ref/doc/uid/3000001300-SW1

《架构之道:三个白线程池池运行员成就微信当当让我们 圈日均10亿发布量[有视频]》 

16年9月底为了出理 ios10 nano crash,研究了libmalloc源码,无意中发现这十几个 接口:

《QQ音乐团队分享:Android中的图片压缩技术详解(上篇)》

大视图是指View的size过大,自身中有 要渲染的内容。超长文本是微信里常见的炸群消息,通常几千甚至几万行。可能把它绘制到同原来View里,那可能消耗少量内存,共同造成严重卡顿。最好做法是把文本划分成多个View绘制,利用TableView的复用机制,减少太满要的渲染和内存占用。

《移动端IM实践:实现Android版微信的智能心跳机制》 

《微信团队原创Android资源混淆工具:AndResGuard [有源码]》 

6)大视图:

传统二叉树是用链表办法实现,每次再加/删除结点,都有申请/释放内存。为了减少内存操作,还不能用数组实现二叉树。具体做法是父结点的左右孩子由以往的指针类型改成整数类型,代表孩子在数组的下标;删除结点时,被删除的结点存放进去原来被释放的结点所在数组下标。

《技术岁月电视剧:“QQ群”和“微信红包”是缘何来的?》 

中间提到,内存监控会带来一定的性能损耗,共同上报的数据量每次大慨3000K左右,全量上报对后台有一定压力,太满对现网用户做抽样开启,灰度包用户/公司内部用户/白名单用户做3000%开启。本地最多只保留最近三次数据。

《微信团队分享:视频图像的超分辨率技术原理和应用场景》

《腾讯团队分享 :一次手Q聊天界面中图片显示bug的追踪过程分享》

《微信Mars:微信内部正在使用的网络层封装库,即将开源》 

《原来微信实习生自述:我眼中的微信开发团队》

《微信当当让我们 圈海量技术之道PPT [附件下载]》 

2.2.3 性能数据

但然后发现,NSData创建对象的类静态办法那么调用+[NSObject alloc],中间实现是调用C办法NSAllocateObject来创建对象,也要是 说同类办法创建的OC对象无法通过hook来获取OC类名。最后在苹果6手机手机4 开源代码CF-1153.18找到了答案,当__CFOASafe=true有之前 __CFObjectAllocSetLastAllocEventNameFunction!=NULL时,CoreFoundation创建对象后通过并都有函数指针告诉上层当前对象是哪几种类型:

据统计,微信运行期间,backtrace的堆栈有成百万上千万种,在捕获最大栈长64清况 下,平均栈长35。可能36bits存储原来地址(armv8最大虚拟内存地址48bits,实际上36bits够用了),原来堆栈平均存储长度157.5bytes,1M个堆栈时要157.5M存储空间。但通过断点观察,实际上大每项堆栈是有共同后缀,同类下面的原来堆栈后7个地址是一样的:

● No pressure, Mon!

《微信团队原创分享:Android版微信后台保活实战分享(线程池池运行运行保活篇)》 

《信鸽团队原创:共同走过 iOS10 上消息推送(APNS)的坑》

《腾讯原创分享(二):怎么才能 才能 大幅压缩移动网络下APP的流量消耗(下篇)》 

微信内存监控最初版本是使用Facebook的FBAllocationTracker工具监控OC对象分配,用fishhook工具hook malloc/free等接口监控堆内存分配,每隔1秒,把当前所有OC对象个数、TOP 3000最大堆内存及其分配堆栈,用文本log输出到本地。该方案实现简单,一天内完成,通过给用户采集TestFlight,最终发现联系人模块因迁移DB加载少量联系人原应FOOM。

所有report计算出型态值后,还不能对它们进行归类了。一级分类还不能是Caller1,也还不能是Category,二级分类是与Caller1/Category有关的型态聚合。效果如下。

《一份微信后台技术架构的总结性笔记》 

2.2.1 存活对象管理

《微信对网络影响的技术试验及分析(论文全文)》 

一级分类:

3)autoreleasepool:

同类外挂是还不能远程控制苹果6手机手机4 的软件,通常一台电脑还不能控制多台手机,电脑画面和手机屏幕实时同步操作,如开启微信,自动加好友,发当当让我们 圈,强制退出微信,并都有过程容易产生误判。出理 办法不到通过安全后台打击不能减少同类误判。

《如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源》 

伸展树(Splay Tree),也叫分裂树,是并都有二叉排序树,不保证树是平衡,但各种操作平均时间错综复杂度是O(logN),可近似看作平衡二叉树。相比太满平衡二叉树(如红黑树),其内存占用较小,不时要存储额外信息。伸展树主要出发点是考虑到局部性原理(某个刚被访问的结点下次又被访问,可能访问次数多的结点下次可能被访问),为了使整个查找时间更少,被频繁查询的结点通过“伸展”操作搬移到离树根更近的地方。大每项清况 下,内存申请太快又被释放,如autoreleased对象、临时变量等;而OC对象申请内存后紧接着会更新它所属Category。太满用伸展树管理最适合不过了。

通过中间办法,当当让我们 的监控数据来源基本跟Allocations一样了,当然是借助了私有API。可能那么足够的“技巧”,私有API带不上Appstore,当当让我们 不到退而求其次。修改malloc_default_zone函数返回的malloc_zone_t型态体里的malloc、free等函数指针,也是还不能监控堆内存分配,效果等同于malloc_logger;而虚拟内存分配不到通过fishhook办法。

c) App那么经常老出crash;

《移动端IM实践:Android版微信怎么才能 才能 大幅提升交互性能(二)》

《让互联网太快:新一代QUIC协议在腾讯的技术实践分享》

《开源libco库:单机千万连接、支撑微信8亿用户的后台框架基石 [源码下载]》 

e) 系统那么升级/重启;

《微信客户端团队负责人技术访谈:怎么才能 才能 着手客户端性能监控和优化》

2.2.2 堆栈存储

《腾讯原创分享(一):怎么才能 才能 大幅提升移动网络下手机QQ的图片传输速率单位和成功率》 

http://www.newosxbook.com/articles/MemoryPressure.html

《腾讯开发微信花了十几个 钱?技术难度真那么大?难在哪?》

>> 更多同类文章 ……

《微信团队原创资源混淆工具:让他的APK立减1M》 

g) App经常老出FOOM。

《移动端IM实践:iOS版微信的多设备字体适配方案探讨》 

《腾讯信鸽技术分享:百亿级实时消息推送的实战经验》

《月活8.89亿的超级IM微信是怎么才能 才能 进行Android端兼容测试的》

[2] 有关QQ、微信的技术故事:

《微信后台基于时间序的海量数据冷热分级采集实践》

(本文同步发布于:http://www.52im.net/thread-1422-1-1.html)

《微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)》 

《微信新一代通信安全出理 方案:基于TLS1.3的MMTLS详解》 

d) 用户那么强退App;

《iOS版微信安装包“减肥”实战记录》 

UIGraphicsBeginImageContext和UIGraphicsEndImageContext时要成双经常老出,不然会造成context泄漏。另外XCode的Analyze不能扫出同类什么的问题。

微信自2017年三月上线内存监控以来,出理 了300多处大大小小内存什么的问题,涉及到聊天、搜索、当当让我们 圈等多个业务,FOOM率由17年年初3%,降到目前0.67%,而前台卡死率由0.6%下降到0.3%,效果有点明显。

《Android版微信安装包“减肥”实战记录》 

2)UIWebView:

3)群控类外挂:

但出理 大分辨率图片时,往往容易经常老出OOM,原应是-[UIImage drawInRect:]在绘制时,先解码图片,再生成原始分辨率大小的bitmap,这是很耗内存的。出理 办法是使用更低层的ImageIO接口,出理 中间bitmap产生:

● UIView数量有无异常

1、2、4、5比较容易判断,3依赖于自身CrashReport组件的crash回调,6、7依赖于ApplicationState和前后台切换通知。

● UIViewController数量有无异常

无论是打开网页,还是执行一段简单的js代码,UIWebView都有占用APP少量内存。而WKWebView不仅有出色的渲染性能,有之前 它有买车人独立线程池池运行运行,太满网页相关的内存消耗移到自身线程池池运行运行里,最适合取替UIWebView。

《微信海量用户转过身的后台系统存储架构(视频+PPT) [附件下载]》

本文来自微信开发团队yangyang的技术分享。

5)大图片出理 :

《2017微信数据报告:日活跃用户达9亿、日发消息33000亿条》

微信自上线FOOM数据上报以来,经常老出不少误判,主要清况 有下面几种。

《以手机QQ为例探讨移动端IM中的“轻应用”》

为了突出什么的问题,提高出理 什么的问题速率单位,后台先根据规则找出可能引起FOOM的Category(如中间的Suspect Categories),规则有:

4)CrashReport组件经常老出crash那么回调上层:

《微信异步化改造实践:8亿月活、单机千万连接转过身的后台出理 方案》 

可能内存监控是存储了当前所有存活对象的内存分配信息,数据量极大,太满当经常老出FOOM时,可能全量上报,要是 按太满规则有选则性的上报。

《微信手机端的本地数据全文检索优化之路》 

《技术岁月电视剧:史上最全QQ图标变迁过程,追寻IM巨人的演进历史》 

通常autoreleased对象是在runloop开始英文时才释放。可能在循环里产生少量autoreleased对象,内存峰值会猛涨,甚至经常老出OOM。适当的再加autoreleasepool能及时释放内存,降低峰值。

《微信技术总监谈架构:微信之道——大道至简(PPT讲稿) [附件下载]》 

当malloc_logger和__syscall_logger函数指针不为空时,malloc/free、vm_allocate/vm_deallocate等内存分配/释放通过这原来指针通知上层,这也是内存调试工具malloc stack的实现原理。有了这原来函数指针,当当让我们 很容易记录当前存活对象的内存分配信息(包括分配大小和分配堆栈)。分配堆栈还不能用backtrace函数捕获,但捕获到的地址是虚拟内存地址,不到从符号表dsym解析符号。太满时要记录每个image加载时的偏移slide,原来 符号表地址=堆栈地址-slide。

>> 更多同类文章 ……

《微信后台团队:微信后台异步消息队列的优化升级实践分享》

2)ApplicationState不准:

也要是 常见的0x8badf00d,通常原应是前台线程池池运行太满,死锁,或CPU使用率持续过低等,同类强杀无法被App捕获。为此当当让我们 结合了已有卡顿系统,当前台运行最后一刻有捕获到卡顿,当当让我们 认为这次启动是被watchdog强杀。共同当当让我们 从FOOM划分出新的重启原应叫“APP前台卡死原应重启”,列入重点关注。

《移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)》

2)轮到插入Stack2,可能G、F、E、D、C结点数据跟Stack1前5结点一致,hash命中;B插入新的7号位置,(B, 5)。Stack2索引入口是7;