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中各部分占用內存問題,當我們得知哪個內存占用比較多,我們直接進行優化即可減少內存占用問題