每次項目編譯完成以後,都被內存搞得頭昏腦脹,壓力甚大。git
利用兩週時間,稍微研究了 微信開源的 MLeaksFinder 和 facebook 開源的 FBMemoryProfiler,github
這兩個開源三方,在編寫過程當中就能夠檢測內存泄露,實在是不要太方便……微信
但願本身在下一個項目能用的駕輕就熟……ide
1. 微信 MLeaksFiner atom
若是對它,你仍是不是很瞭解 ,能夠到查閱這裏: http://wereadteam.github.io/2016/07/20/MLeaksFinder2/ ;spa
1.1 建立demo 項目 LeakDemo 引入 MLeaksFiner 開源文件夾debug
->本次 我是直接下載到本地了,因此直接拖拽到了項目3d
1.2 引入這個開源文件後 ,不用寫多餘的代碼,默認debug 編譯的時候,自動啓動使用orm
下面來寫一段內存泄露的代碼,進行試驗::對象
內存泄露的代碼::
在 main.storybord 中添加 NavigationController
VC 代碼 ViewController .m ::
#import "ViewController.h" #import "FirstController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.navigationItem.title = @"vc"; [self creatButton]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } -(void)creatButton{ UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 100, 100)]; [self.view addSubview:button]; button.center = self.view.center; [button setTitle:@"下一頁" forState:UIControlStateNormal]; button.backgroundColor = [UIColor yellowColor]; [button addTarget:self action:@selector(didButtonClick:) forControlEvents:UIControlEventTouchUpInside]; } -(void)didButtonClick:(UIButton*)btn{ NSLog(@"vc btn Click"); [self.navigationController pushViewController:[FirstController new] animated:true]; }
新建 FirstController :
#import "FirstController.h" #import "TestView.h" @interface FirstController () @property (nonatomic,strong)TestView *testView; @end @implementation FirstController - (void)viewDidLoad { [super viewDidLoad]; self.navigationItem.title = @"first vc"; self.view.backgroundColor = [UIColor whiteColor]; [self addTestView]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } -(void)addTestView{ self.testView = [[TestView alloc]initWithFrame:CGRectMake(0, 0, 200, 30)]; self.testView.vc = self; [self.view addSubview:self.testView]; self.testView.center = self.view.center; }
@end
新建 TestView :
TestView .h
#import <UIKit/UIKit.h>
#import "FirstController.h"
@interface TestView : UIView
@property (nonatomic,strong)FirstController *vc;// 把這個屬性 換成 strong 屬性 故意形成 泄露
@end
TestView .m
#import "TestView.h" @implementation TestView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self prepareUI]; } return self; } -(void)prepareUI{ self.backgroundColor = [UIColor redColor]; } @end
內存泄露的解釋::::
vc -> push -> first VC
:( first vc 強持有 testView ,testView 強持有 firstVc : 彼此強持有,沒法釋放)
-> pop 回-> vc
=》: first vc 沒法釋放
1.3 檢測 到泄露 alert 方式體提醒 :::
這裏檢測到是有 循環泄露的,可是沒法準肯定位泄露的對象
因此繼續……
2 . MLeakFinder + FBRetainCycleDetector
2.1 查閱了 MLeaksFinder.h 的文件
這段宏定義的解釋 https://www.jianshu.com/p/e3dbf58982f6:::
#ifdef MEMORY_LEAKS_FINDER_ENABLED //_INTERNAL_MLF_ENABLED 宏用來控制 MLLeaksFinder庫 //何時開啓檢測,能夠自定義這個時機,默認則是在DEBUG模式下會啓動,RELEASE模式下不啓動 //它是經過預編譯來實現的
#define _INTERNAL_MLF_ENABLED MEMORY_LEAKS_FINDER_ENABLED #else #define _INTERNAL_MLF_ENABLED DEBUG #endif
//_INTERNAL_MLF_RC_ENABLED 宏用來控制 是否開啓循環引用的檢測
#ifdef MEMORY_LEAKS_FINDER_RETAIN_CYCLE_ENABLED #define _INTERNAL_MLF_RC_ENABLED MEMORY_LEAKS_FINDER_RETAIN_CYCLE_ENABLED //COCOAPODS 由於MLLeaksFinder引用了第三庫用來檢查循環引用,因此必須是當前項目中使用了COCOAP //ODS,才能使用這個功能。 #elif COCOAPODS #define _INTERNAL_MLF_RC_ENABLED COCOAPODS #endif
2.2 . 添加cocopod ,而後 Pod 添加 FBRetainCycleDetector;
註釋 這兩段代碼 == 》同時開啓 MLeakfinder 檢測 和 retainCycle 檢測
//#define MEMORY_LEAKS_FINDER_ENABLED 0 #ifdef MEMORY_LEAKS_FINDER_ENABLED #define _INTERNAL_MLF_ENABLED MEMORY_LEAKS_FINDER_ENABLED #else #define _INTERNAL_MLF_ENABLED DEBUG #endif //#define MEMORY_LEAKS_FINDER_RETAIN_CYCLE_ENABLED 0 #ifdef MEMORY_LEAKS_FINDER_RETAIN_CYCLE_ENABLED #define _INTERNAL_MLF_RC_ENABLED MEMORY_LEAKS_FINDER_RETAIN_CYCLE_ENABLED #elif COCOAPODS #define _INTERNAL_MLF_RC_ENABLED COCOAPODS #endif
從新編譯運行 彈框是這樣
正確找到 循環引用 cycle
最簡單的使用方法了吧,先使用着,有機會會研究下 源碼 ^ V ^