博文連接:FBMemoryProfiler 基礎教程ios
FBMemoryProfiler是Facebook開源的一款用於分析iOS內存使用和檢測循環引用的工具庫。git
在上一篇[譯文]在iOS上自動檢測內存泄露中,Facebook講解了FBMemoryProfiler的核心原理。鑑於有人在評論裏問怎麼使用,我這裏就簡單介紹一下。github
建議使用Cocoapods安裝,只須要在pod文件中,添加這麼一句就行:數組
pod 'FBMemoryProfiler'
FBMemoryProfiler
最低支持iOS8,因此若是你的pod文件上最低要求是6或者7的話,是沒法直接安裝的。因此,建議在開發分支或者若是你有多個target的話,在開發的target上添加FBMemoryProfiler
,在生產的target上不須要添加FBMemoryProfiler
。服務器
我通常習慣於有兩個target,一個用於開發,裏面可能會包含Reveal
、蒲公英等的庫,而這在生產包中是沒必要要的,另外一個用於生產,只用於打生產包。app
因此個人pod文件多是這樣的:ssh
# Uncomment this line to define a global platform for your project platform :ios, '8.0' # Uncomment this line if you're using Swift # use_frameworks! target 'FBMemoryProfilerTest' do end target 'FBMemoryProfilerTest_Dev' do pod 'FBMemoryProfiler' end
安裝成功以後,打開對於的.xcworkspace
文件便可。ide
若是你的app從iOS8開始支持的話,你可使用Carthage
來安裝。工具
在建立的Cartfile
文件中添加:測試
github "facebook/FBMemoryProfiler"
以後,運行carthage update --configuration Debug
便可。
由於個人app要從iOS6開始支持,因此我沒有使用這個。
首先,要在main.m
中添加FBRetainCycleDetector
的hook,同時,也要開啓FBAllocationTracker
的生成追蹤:
#import <UIKit/UIKit.h> #import "AppDelegate.h" #if DEBUG #import <FBAllocationTracker/FBAllocationTrackerManager.h> #import <FBRetainCycleDetector/FBRetainCycleDetector.h> #endif int main(int argc, char * argv[]) { @autoreleasepool { #if DEBUG [FBAssociationManager hook]; [[FBAllocationTrackerManager sharedManager] startTrackingAllocations]; [[FBAllocationTrackerManager sharedManager] enableGenerations]; #endif return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
我習慣於添加一個DEBUG標識符,只在Debug狀態纔開啓FBMemoryProfiler
。固然,你能夠不須要。
以後,咱們要在AppDelegate.m
的application: didFinishLaunchingWithOptions:
中嵌入FBMemoryProfiler
的建立代碼:
#if DEBUG #import <FBMemoryProfiler/FBMemoryProfiler.h> #import <FBRetainCycleDetector/FBRetainCycleDetector.h> #import "CacheCleanerPlugin.h" #import "RetainCycleLoggerPlugin.h" #endif @interface AppDelegate () { #if DEBUG FBMemoryProfiler *memoryProfiler; #endif } @end @implementation AppDelegate -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { #if DEBUG memoryProfiler = [[FBMemoryProfiler alloc] initWithPlugins:@[[CacheCleanerPlugin new], [RetainCycleLoggerPlugin new]] retainCycleDetectorConfiguration:nil]; [memoryProfiler enable]; #endif return YES; } @end
其中,插件是能夠不開啓的,若是你不想開啓的話,你能夠這麼寫:
FBMemoryProfiler *memoryProfiler = [FBMemoryProfiler new]; [memoryProfiler enable];
插件主要是用來進行過濾、去重或者輸出、存儲等操做的,畢竟若是不開啓插件的話,只能經過在手機、模擬器上點擊屏幕來看內存泄露,而若是自定義log插件的話,能夠將捕獲到的內存泄露輸出到控制檯或者文件中。
好比說,咱們能夠自定義一個RetainCycleLoggerPlugin
,使用FBMemoryProfilerPluggable
協議,重寫memoryProfilerDidFindRetainCycles:
方法:
-(void)memoryProfilerDidFindRetainCycles:(NSSet *)retainCycles { if (retainCycles.count > 0) { NSLog(@"\nretainCycles = \n%@", retainCycles); } }
當FBRetainCycleDetector
找到循環引用以後,就會調用到上面的方法,可是,retainCycles
多是個空集合,因此這裏能夠過濾一下。
我在測試個人app的時候,發現這樣一個問題:
我確信這裏沒有由於我而致使的循環引用,可是FBRetainCycleDetector
在這裏檢測到了這個環,這裏的主要問題在於_subviewCache
,這是蘋果的機制,可是並不會形成內存泄露。對於這種狀況,咱們須要將它過濾出去。
除此以外,還有一個Timer
的問題,由於通常狀況下,Timer
會強引用target,因此可能致使內存泄露,若是你確信沒有問題的話,能夠關閉對Timer
的檢測。
過濾代碼相似於這種:
NSArray *filters = @[FBFilterBlockWithObjectIvarRelation([UIView class], @"_subviewCache")]; FBObjectGraphConfiguration *configuration = [[FBObjectGraphConfiguration alloc] initWithFilterBlocks:filters shouldInspectTimers:YES]; memoryProfiler = [[FBMemoryProfiler alloc] initWithPlugins:@[[CacheCleanerPlugin new], [RetainCycleLoggerPlugin new]] retainCycleDetectorConfiguration:configuration]; [memoryProfiler enable];
咱們只須要設置一個過濾數組,而後添加到FBMemoryProfiler
的Configuration
中便可。
對於你確信沒有問題或者不想修改的問題,你能夠在Configuration
中直接過濾掉。
好比:
NSArray *filters = @[FBFilterBlockWithObjectIvarRelation([UIPanGestureRecognizer class], @"_internalActiveTouches")];
若是你有CI的須要,你能夠在代理中輸出log到文本,以後傳出到服務器上。
具體操做能夠參考Facebook的視頻,上一篇譯文中也有給出。
上面說到的代碼放在了這個demo中:
https://github.com/Forkong/FBMemoryProfilerDemo
git clone
以後須要 pod install
一下,才能夠運行。