FBMemoryProfiler 基礎教程

博文連接:FBMemoryProfiler 基礎教程ios

FBMemoryProfiler是Facebook開源的一款用於分析iOS內存使用和檢測循環引用的工具庫。git

在上一篇[譯文]在iOS上自動檢測內存泄露中,Facebook講解了FBMemoryProfiler的核心原理。鑑於有人在評論裏問怎麼使用,我這裏就簡單介紹一下。github

安裝

CocoaPods

建議使用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

Carthage

若是你的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.mapplication: 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];

咱們只須要設置一個過濾數組,而後添加到FBMemoryProfilerConfiguration中便可。

對於你確信沒有問題或者不想修改的問題,你能夠在Configuration中直接過濾掉。

好比:

NSArray *filters = @[FBFilterBlockWithObjectIvarRelation([UIPanGestureRecognizer class], @"_internalActiveTouches")];

若是你有CI的須要,你能夠在代理中輸出log到文本,以後傳出到服務器上。

運行

具體操做能夠參考Facebook的視頻,上一篇譯文中也有給出。

操做視頻

代碼

上面說到的代碼放在了這個demo中:

https://github.com/Forkong/FBMemoryProfilerDemo

git clone 以後須要 pod install 一下,才能夠運行。

相關文章
相關標籤/搜索