Instruments学习之Allocations

注意:这个工具非常有用,文本也是一个超长文

Allocations初始界面

Allocations:检测一个进程(选择自己的app)内存分配和使用情况等
我们启动Allocations后得到一个初始界面


初始界面.png

简单说一下上图的3个地方
1:这里有两个部分了,因为官方说了Allocations(上面)和垃圾数据占用(下面)一起展示更好分析
2:一个列表,展示了哪些方法\部分消耗了多少内存,前面的钩钩上会在1部分显示出主柱状图,自己点一下就知道了,不截图
3:设置和扩展功能,文章后面慢慢讲

开始分析列表

我先随意的在自己app中点击,跳转等操作,然后截个图如下


分析图.png

我们可以惊讶的看到All Heap Allocations(真实内存)只有23.02,而All Anonymous VM(虚拟内存:为程序分配的虚拟内存,当程序有需要的时候,能够及时为程序提供足够的内存空间,而不会现用现创建)高达91.06,所以手机分配给我们的内存是114.08;我们现在不检测内存泄漏(是另外一个工具),所以我们尽量优化VM(因为不是app真实占用的内存,只是系统分配的),而VM主要由以下三部分组成(我会把三部分都优化完了后再运行截图)

VM:ImageIO_PNG_Data

关于这个问题我在google中找到了解释,说到

Replace:
background.image = [UIImage imageNamed:@"*.png"];
With:
background.image = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/*.png"]];
and now the ImageIO_PNG_Data's will be released when the view controller is dismissed.

我后面在我工程中搜索了一下imageNamed,确实有很多地方使用了,所以我们加载图片正确的思路应该是这样

1:对于大的图片且偶尔需要显示的应放到工程目录下,不要放到Assets.xcassets中;并使用imageWithContentsOfFile加载不让系统缓存
2:对于经常需要展示的小图片放到Assets.xcassets中让系统缓存,使用imageNamed加载

所以我改了一些地方,比如

imageView.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:nameArr[index] ofType:@"png"]];
//imageView.image = [UIImage imageNamed:nameArr[index]];

VM:CG raster data

关于这个问题我在google中找到了解释,这是SDWebImage的问题

* Decompressing images that are downloaded and cached can improve peformance but can consume lot of memory.
* Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption.

所以我们需要在Appdelegate中设置一下

[[SDImageCache sharedImageCache] setShouldDecompressImages:NO];
[[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO];
[[SDImageCache sharedImageCache] setShouldCacheImagesInMemory:NO];

VM:CoreAnimation

这个问题在google搜索的时候没有明显的答案,我们先查看一下详细列表

进入详情列表.png
我们可以看到很多的地方都有这个VM问题,那我们具体看一下是哪些函数
具体查看调用栈.png
我们可以发现都是系统的一些方法,我们好像无从下手;这时候我们可以google看看发现有很多原因都会变成这个样子,其中一个是这里

Found out that animation caused by the inner pages.
Inside the pageViewController(viewController that added to the scrollView as a page) on viewWillDisappear:(BOOL)animated method I added this
for (CALayer* layer in [self.view.layer sublayers]) {
        [layer removeAllAnimations];
}
it resolved the problem.

其中的Found out that animation caused by the inner pages我们还是需要在扩展信息中查看能不能定位到某个页面(我不知道怎么定位,如果你知道请一定回复我),所以我在我刚才进入过的界面全部实现了如上方法

看看优化结果

这时候我们重新启动Allocations,然后重复上面随意的在自己app中点击,跳转等操作,然后截图如下


VM优化结果.png

我们发现一个好的现象VM:CG raster data明显减少了;同时我们得到一个坏现象,其他两项并没有明显变化,那我们继续分析什么原因,不过不要着急,我们先来看看右下方都有哪些功能

Record Settings

Launch Configuration for All Allocations

所有的Allocations启动如下配置:
Discard unrecorded data upon stop:当用户点击停止的时候丢弃没有记录的数据,勾不勾无所谓
Discard events for freed memory:当内存被释放的时候丢弃事件(也就是列表中不显示已被释放内存所关联的事件)
Only track VM allocations:只捕获虚拟内存的项,不勾,因为我们还是需要看看真实内存占用的
这里我们需要把第一、二个勾上

Launch Configuration for Heap Allocations

对所有的真实内存Allocations启动如下配置(如果你钩中了Only track VM allocations,这一栏是没办法操作的):
Record reference counts:记录引用计数
Identity virtual C++ objects:标记虚拟c++对象,这个钩上可以检测openGL等库
Enable NSZombie detection:检测僵尸对象,钩上可以发现有没有对已释放的对象发送消息

Recorded Types

这个我就不需要解释了,你需要捕获什么类型的事件就钩上,提供了简单的正则

Dispalay Settings

Track Display

决定上面将要显示什么内容


上面显示什么内容.png

Current Bytes:显示字节数量
Allocation Density:Allocation数量
Active Allocation Distribution:新激活的Allocation数量

Generation Analysis

这个功能是非常有用的,一般是这样用的:进入一个页面前mark一下,在退出这个页面的时候再mark一下可以比较哪些内容增加了,就可以具体分析哪些内存没有被释放;比如我们要进入日程界面的时候我点了一下mark


列表自动切换了.png

显示了Growth(相比上一次增加的量)为27.48,也就是第一次真实内存和虚拟内存之和;我们在日程界面操作一阵子之后我们再点击mark截图


再次mark.png
所以我们知道了我们退出日程界面内存依然还是增加了2.85,你可以点击查看具体是哪些增加了
哪些增加了.png

Allocation Lifespan

需要记录哪些Allocation
All Allocations:所有的
Created & Persistent:创建且存活的
Created & Destroyed:创建且被销毁的
我们目前只关心存活的,所以我们钩上第二个

Allocation Type

记录的Allocation类型
All Heap & Anonymous VM:所有真实内存和虚拟内存,我通常选这个分析
All Heap Allocations:所有真实内存
All VM Regions:所有分配过的虚拟内存
这里的选择将会影响到列表,比如我选择All VM Regions


只显示虚拟内存.png

Call Tree

这里的功能需要我们把列表展示类型切换成Call Trees,能够非常清晰的看到调用树


调用树展示.png

不过一般我们需要勾选一些选项,因为默认的实在看不出什么东西
Separate by Category:按照类别隔开,我们钩上看看效果


按照类别隔开.png
瞬间好看多了,我们能够清楚的看出来是哪些类别的VM
Separate by Thread:按照线程划分,我个人不是很喜欢这种划分,因为我不是很关心线程

Invert Call Tree:反转调用,我们给一张对比图就不需要解释了


未钩中.png

钩中.png
我习惯钩上,因为我能够一眼看到具体哪个方法出现了问题
Hide System Libraries:这个似乎是必钩的,因为我们目前只关心自己的方法,不关心系统的
Flatten Recursion:扁平化递归,我暂时还不知道是干嘛的,网上也没有搜到,不过我还是钩上了,听着是一个不错的功能

Call Tree Constraints

这个我就不需要讲了,是对列表中的数据进行过滤,可以是数量和大小;比如我只关心100以内的数据


100之内的数据png

Data Mining

数据挖掘,这是一个很具有噱头的功能;官网给了这么一个解释

Allows you to filter through the collected data for specific symbols and libraries.

就是可以过滤掉你不看的库、符号调用
点击Symbol、Library会自动把你选中的行的符号、库加到小框中


例子.png

符号和库有两个选项,就是是否过滤改行;点击Restore会去掉小框中的选中行,比如我们把帮帮管理助手去掉
去掉某行.png
我觉得我暂时用不到数据挖掘,所以我后面熟悉了的时候再来补充这部分

Extended Detail

这个我其实已经介绍过了,对于Allocations来说是看某一条数据的调用栈等信息
到现在我们只有一种列表展示没有介绍了,我们来看一眼


Allocations List类型.png

相对于Statistics来说多了调用库和方法的展示

继续优化

刚才说到了,我们只对VM:CG raster data的优化表示满意,接下来我们继续优化VM:CoreAnimation和VM:ImageIO_PNG_Data

VM:ImageIO_PNG_Data优化

前面说到我们把加载大图片的方法换成了imageWithContentsOfFile但是效果不明显,现在我们就来看看具体是哪个方法产生了大量的虚拟内存,下面是步骤

查看列表

找到调用函数.png
在谷歌借鉴了解决方法

//_pageScrollView是一个滚动视图,用来加载本地图片
...
//加入图片
    for (int index = 0; index < nameArr.count; index ++) {
        UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(index * pageScrollImagewidth, 0, pageScrollImagewidth, pageScrollImageheight)];
         NSString *imageFile = [NSString stringWithFormat:@"%@/%@.png",[[NSBundle mainBundle] resourcePath],nameArr[index]];
        @autoreleasepool {
             imageView.image = [UIImage imageWithContentsOfFile:imageFile];
        }
//        imageView.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:nameArr[index] ofType:@"png"]];
//        imageView.image = [UIImage imageNamed:nameArr[index]];
        [_pageScrollView addSubview:imageView];
    }
...
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    for (UIView *viewView in _pageScrollView.subviews) {
        [viewView removeFromSuperview];
    }
    _pageScrollView = nil;
}

按照这个方法后,效果还是很明显的,之前是33.95(看文章前面的图)


减少了很多.png

优化VM:CoreAnimation

我们同样用Generations检测出了这个问题


内存增加的主要内容.png

前面说到我们谷歌到可以采用下面的方法减少

for (CALayer *layer in self.view.layer.sublayers) {
        [layer removeAllAnimations];
    }

但是证明几乎没用,那我们只好继续谷歌看看,按照上面的方法,我们在谷歌输入关键字CA::Render::Shmem::new_shmem(unsigned long)进行搜索,我们从搜索的结果可以得知这是一个很多原因都会导致的结果;其中在这篇文章有两段描述

the solution is to reduce that space to an absolute minimum.
//把控件的范围设置到最小
...
I am having the same issue. I will try what you suggested with the size. 
But, maybe changing the background color from clearColor could 
correct the issue as well.
//改变视图的背景颜色

我试了改变背景颜色,没什么作用

[[UIView appearance] setBackgroundColor:[UIColor whiteColor]];
[[UIView appearance] setBackgroundColor:[UIColor clearColor]];

所以我们就暂时不解决这个了,我后面解决了会在这里进行补充,VM:Animation优化是一个大问题,可能需要一篇文章单独讲

看另一部分

接下来我们来看看这个视图是干什么用的,使用的时候需要手动捕获(或者你钩上Automatic Snapshotting自动定时捕获)一次左下角列表才有数据

捕获一次.png
默认会显示三种数据
Dirty Size:脏数据大小(没办法被重复使用)
Swapped Size:交换空间大小
Resident Size:固定数据大小
关于这三个名字的解释,你可以看看这里,所以我们得知这条数据是有异常的
异常数据.png
因为产生了31.54的垃圾数据,我们在这里找到了想要的答案,结果证明无效
又从这里得知我们不需要管这个问题,因为这时XCode工具自身的,不是我们程序的
所以我们来看下一个问题
下一个问题.png
我还特别重新启动了一次,证明我确实没有做什么其他操作,结果垃圾数据还是很多
malloc开头的.png
这是为什么呢?答案在这里,所以这一部分我们也不需要管,所以我们的程序没有出现大量垃圾数据情况,问题还是出在CoreAnimation
CoreAnimation问题.png
我们把这个问题留着, 因为和上面优化VM:CoreAnimation是一类问题,等我熟悉了我再补充

Regoins Map

Regoins Map视图.png

这个视图,主要是把每一条数据的地址段和调用路径给你显示出来了,我很少用这个视图,不过能看到path还是不错的

Allocations一般来做什么

其实文本已经大致讲了一下,Allocations对app优化非常有用,通常是拿来分析内存增加(不一定是内存泄漏)和app中各部分占用内存问题,当我们得知哪个内存占用比较多,我们直接进行优化即可减少内存占用问题
本文一直在讨论如何减少VM的占用,你接下来可以分析Heap占用

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

推荐阅读更多精彩内容