iOS内存深入探索之内存用量

前言

我们在查看iOS应用内存时,最常见的手法就是查看左边的Debug Navigator。不知你是否也曾困惑于这个内存究竟包括哪些部分,或者使用Allocations模版观察内存时发现无法和Debug Navigator显示的内存匹配上,这篇文章将带你解答这些疑惑。


Debug Navigator VS Allocations

我们运行一个很简单的iOS App,我只在ViewController中放置了一个View,然后对比下Debug Navigator 和 Allocations给出的内存用量。



可以发现,Debug Navigator给出的是79.3M,而Allocations统计的所有堆和相关VM加起来才38.72M,相差的还是很多的。在之前的文章中我有介绍关于AllocationsVM Tracker的深入理解,其实Allocations中主要包含的是所有MALLOC_XXX VM Region和部分App进程创建的VM Region。非动态的内存,以及部分其他动态库创建的VM Region并不在Allocations的统计范围内。比如主程序或者动态库的_DATA数据段,这些数据内存区域并非通过malloc分配,也就没有统计在All Heap Allocations中,所以你会发现All Heap Allocations往往会比较小。除非你自行使用malloc系列方法创建大内存块,否则很难看到All Heap Allocations有一个大的数值。我们在实际的App中,大的内存占用一般都是类似于WebKit,ImageIO,CoreAnimation等虚拟内存区域(VM Region),这些VM Region一般由系统代码生成和管理,我们编写的代码如果间接引用了这些内存而没有释放,也就会造成大面积的内存泄漏。

Debug Navigator VS VM Tracker

接下来我们来看看VM Tracker统计的内存如何,下面是截图。


在看VM Tracker时,我们主要看Dirty Size和Swapped Size,由于我是在模拟器上调试的,所以才需要关注Swapped Size,在手机上,主进程的内存应该是不会交换到硬盘上的,内存不足时,会触发内存警告。Dirty Size主要指的是不可被重新载入的内存区域大小,比如函数栈,如果你把函数栈的数据给抹掉了,也就无法恢复之前的函数调用栈数据了,这种可以称为Dirty内存区域,但如果是通过文件内存映射载入到内存区域的,可以先清除掉这部分内存里的数据暂时把这部分内存给别人用,需要时再从文件载入到内存,这种内存区域可以认为是非Dirty的。Dirty Size可以代表一个进程需求的最少内存量,当然在模拟器上,还要加上被交换出去的数据大小,即Swapped Size。
我们回到上图,VM Tracker给出的Dirty Size总量时69.79M,还是和79.3M有些差距。不过我们可在在图中看到_DATA数据段,Stack(函数栈)等等Allocations没有统计的内存区域。

Debug Navigator VS vmmap command line

苹果除了Instrument的VM Tracker可以查看虚拟内存之外,还有一个vmmap命令行可以查看进程的虚拟内存分配。使用模拟器启动App,通过Activity Monitor找到App的进程ID,比如1364,使用vmmap查看它的虚拟内存分配。

vmmap 1364 

结果如下

...
                                VIRTUAL RESIDENT    DIRTY  SWAPPED VOLATILE   NONVOL    EMPTY   REGION 
REGION TYPE                        SIZE     SIZE     SIZE     SIZE     SIZE     SIZE     SIZE    COUNT (non-coalesced) 
===========                     ======= ========    =====  ======= ========   ======    =====  ======= 
Activity Tracing                   256K      36K      36K      12K       0K      36K       0K        2 
CoreAnimation                     36.1M    33.3M    33.3M    2848K       0K    33.3M       0K        2 
Kernel Alloc Once                    8K       8K       8K       0K       0K       0K       0K        2 
MALLOC guard page                   48K       0K       0K       0K       0K       0K       0K       13 
MALLOC metadata                    260K      92K      92K      32K       0K       0K       0K       16 
MALLOC_LARGE                      4360K    4256K    4256K     104K       0K       0K       0K        3         see MALLOC ZONE table below
MALLOC_LARGE (empty)              3988K    2080K    2080K    1908K       0K       0K       0K        2         see MALLOC ZONE table below
MALLOC_LARGE metadata                4K       4K       4K       0K       0K       0K       0K        2         see MALLOC ZONE table below
MALLOC_NANO                       16.0M    2160K    2160K       0K       0K       0K       0K        3         see MALLOC ZONE table below
MALLOC_SMALL                      40.0M     840K     840K     356K       0K       0K       0K        3         see MALLOC ZONE table below
MALLOC_TINY                       8192K     320K     320K      36K       0K       0K       0K        3         see MALLOC ZONE table below
Performance tool data              316K     264K     264K      52K       0K       0K       0K        3         not counted in TOTAL below
STACK GUARD                       56.0M       0K       0K       0K       0K       0K       0K        4 
Stack                             9232K      76K      76K      20K       0K       0K       0K        7 
__DATA                            35.4M    16.6M    16.4M    12.3M       0K       0K       0K      282 
__FONT_DATA                          4K       0K       0K       0K       0K       0K       0K        2 
__LINKEDIT                        96.0M    69.5M       0K       0K       0K       0K       0K      225 
__TEXT                           228.3M    54.4M       4K       4K       0K       0K       0K      225 
__UNICODE                          560K     320K       0K       0K       0K       0K       0K        2 
mapped file                       28.7M    2116K       0K       0K       0K       0K       0K        3 
shared memory                       44K      24K      24K       8K       0K       0K       0K        5 
===========                     ======= ========    =====  ======= ========   ======    =====  ======= 
TOTAL                            562.9M   185.8M    59.3M    17.5M       0K    33.4M       0K      786 

我们将Dirty Size和Swapped Size总量相加59.3M + 17.5M = 76.8M,和Debug Navigator给的值已经很相近了,我们再看上面的表格,发现有一行是这么写的Performance tool data ... not counted in TOTAL belowPerformance tool data并没有统计在最下面的TOTAL中,因为这些数据是Debug时提供调用回溯数据用的,所以vmmap默认认为没有价值,没有统计。但是Debug Navigator不这么认为,我们加上Performance tool data的内存用量,264K + 52K = 316K = 0.308M,加上之前的76.8M就是77.108M,由于本次并没有使用Instruments进行profile,所以占用的内存会少一些,Debug Navigator显示的刚好是77.1M。至于为什么vmmap显示的数据要比Instruments VM Tracker的要完整,目前我还没有明确的答案。

shared memory

最后我要提到的时共享内存,共享内存可以提供跨进程访问的能力,不过如果你的App使用了别的进程创建的共享内存,那么Debug Navigator是不会将它计入你自己的内存总量的,不过vmmap会将它加入TOTAL中,所以可能会导致vmmap计算的内存量会大于Debug Navigator统计内存量。由于目前iOS对于shared memory的一些API并不支持,我也没有深入研究,只是在OSX中验证了这一点。

总结

最后来总结一下,Debug Navigator其实就是统计了当前进程的所有虚拟内存的Dirty Size + Swapped Size,当然还要剔除掉对第三方共享内存的使用量,当我们发现Debug Navigator的内存量飙高时,不仅仅要去关注Heap上的内存用量,更要关注VM Tracker中那些大Dirty Size的VM Region,这样才能更透彻的了解你的App究竟是怎样使用内存的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容