成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術文章
文章詳情頁

IOS內存泄漏檢查方法及重寫MLeakFinder

瀏覽:7日期:2022-09-16 16:21:09

對于iOS開發來講,內存泄漏的問題,已經是老生常談的話題。在日常的面試中經常會提到這些問題。我們日常的開發過程中進行內存泄漏的檢測,一般是使用instrument工具中的Leaks/Allocation來進行排查,網絡上也有比較高效又好用的內存泄漏檢測工具,MLeakFinder。

MLeakFinder-原理

首先看UIViewController,當一個UIViewController被pop或dismiss的時候,這個VC包括在這個VC上的View,或者子View都會很快的被釋放。所以我們我們需要在UIViewController被POP或dismiss后一小段時間后,在這個VC上的view,subView等是否還存在。

在UIViewController+MemoryLeak.h的load方法中可以看到,早+load方法中通過runtime交換了viewWillAppear,viewDidAppear,dismissViewControllerAnimated:completion:這三個方法。

1,首先看viewWillAppear

- (void)swizzled_viewWillAppear:(BOOL)animated { [self swizzled_viewWillAppear:animated]; objc_setAssociatedObject(self, kHasBeenPoppedKey, @(NO), OBJC_ASSOCIATION_RETAIN);}

當VC進來的時候,添加關聯對象,并標記為NO

2,在看viewDidAppear

- (void)swizzled_viewDidDisappear:(BOOL)animated { [self swizzled_viewDidDisappear:animated]; if ([objc_getAssociatedObject(self, kHasBeenPoppedKey) boolValue]) {[self willDealloc];}}

通過代碼可以看出,獲取當前關聯對象的標記,當標記為YES的時候,就會調用willDealloc。

3,我們看什么時候會被標記為YES呢?

在UINavigationController+MemoryLeak.h的popViewControllerAnimated:方法中我們可以看到

- (UIViewController *)swizzled_popViewControllerAnimated:(BOOL)animated { UIViewController *poppedViewController = [self swizzled_popViewControllerAnimated:animated]; if (!poppedViewController) {return nil; } // Detail VC in UISplitViewController is not dealloced until another detail VC is shown if (self.splitViewController &&self.splitViewController.viewControllers.firstObject == self &&self.splitViewController == poppedViewController.splitViewController) {objc_setAssociatedObject(self, kPoppedDetailVCKey, poppedViewController, OBJC_ASSOCIATION_RETAIN)return poppedViewController; } // VC is not dealloced until disappear when popped using a left-edge swipe gesture extern const void *const kHasBeenPoppedKey; objc_setAssociatedObject(poppedViewController, kHasBeenPoppedKey, @(YES), OBJC_ASSOCIATION_RETAIN); return poppedViewController;}

我們可以看出,在VC被pop或者左滑返回的時候,相當于視圖銷毀,就會被標記為YES。

4,我們重點看willDealloc

- (BOOL)willDealloc { //第一步 NSString *className = NSStringFromClass([self class]); if ([[NSObject classNamesWhitelist] containsObject:className])return NO; //第二步 NSNumber *senderPtr = objc_getAssociatedObject([UIApplication sharedApplication], kLatestSenderKey) if ([senderPtr isEqualToNumber:@((uintptr_t)self)])return NO; //第三步 __weak id weakSelf = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{__strong id strongSelf = weakSelf;[strongSelf assertNotDealloc]; }); return YES;}

1.第一步:我們可以看到,會先判斷當前的class是否在白名單中,是的話就會return NO,即不是內存泄漏的。同時我們查看構建白名單的源碼:使用了一個單例實現,確保只有一個,是個私有方法

+ (NSMutableSet *)classNamesWhitelist { static NSMutableSet *whitelist = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{whitelist = [NSMutableSet setWithObjects: @'UIFieldEditor', // UIAlertControllerTextField @'UINavigationBar', @'_UIAlertControllerActionView', @'_UIVisualEffectBackdropView', nil];// System’s bug since iOS 10 and not fixed yet up to this ci.NSString *systemVersion = [UIDevice currentDevice].systemVersion;if ([systemVersion compare:@'10.0' options:NSNumericSearch] != NSOrderedAscending) { [whitelist addObject:@'UISwitch'];} }); return whitelist;}

同時在還支持,自定義的添加白名單

+ (void)addClassNamesToWhitelist:(NSArray *)classNames { [[self classNamesWhitelist] addObjectsFromArray:classNames];}

2. 第二步:判斷該對象是否是上一次發送action的對象,是的話,不進行內存檢測

//第二步 NSNumber *senderPtr = objc_getAssociatedObject([UIApplication sharedApplication], kLatestSenderKey) if ([senderPtr isEqualToNumber:@((uintptr_t)self)])return NO;

3,第三步:弱指針指向self,2s延遲,然后通過這個弱指針調用-assertNotDealloc,若被釋放,給nil發消息直接返回,不觸發-assertNotDealloc方法,認為已經釋放;如果它沒有被釋放(泄漏了),-assertNotDealloc就會被調用

__weak id weakSelf = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{__strong id strongSelf = weakSelf;[strongSelf assertNotDealloc]; });5,現在我們回到:2的代碼 [self willDealloc]

看一下他的源碼

- (BOOL)willDealloc { //第一步 if (![super willDealloc]) {return NO; } //第二步 [self willReleaseChildren:self.childViewControllers]; [self willReleaseChild:self.presentedViewController]; if (self.isViewLoaded) {[self willReleaseChild:self.view]; } return YES;}

1,第一步:會通過 super調用父類的willDealloc,即上面目錄4

2,第二步:調用willReleaseChildren,willReleaseChild遍歷該對象的子對象,看其是否釋放

- (void)willReleaseChild:(id)child { if (!child) {return; }[self willReleaseChildren:@[ child ]];}- (void)willReleaseChildren:(NSArray *)children { NSArray *viewStack = [self viewStack]; NSSet *parentPtrs = [self parentPtrs]; for (id child in children) {NSString *className = NSStringFromClass([child class]);[child setViewStack:[viewStack arrayByAddingObject:className]];[child setParentPtrs:[parentPtrs setByAddingObject:@((uintptr_t)child)]];[child willDealloc]; }}

通過代碼可以看出,通過調用willReleaseChildren的方法,獲取當前對象viewStack,parentPtrs,并且遍歷children,為每個子對象設置viewStack,parentPtrs,然后調用willDealloc。

通過源碼看一下viewStask,parentPtrs的實現

- (NSArray *)viewStack { NSArray *viewStack = objc_getAssociatedObject(self, kViewStackKey); if (viewStack) {return viewStack; }NSString *className = NSStringFromClass([self class]); return @[ className ];}- (void)setViewStack:(NSArray *)viewStack { objc_setAssociatedObject(self, kViewStackKey, viewStack, OBJC_ASSOCIATION_RETAIN);}- (NSSet *)parentPtrs { NSSet *parentPtrs = objc_getAssociatedObject(self, kParentPtrsKey); if (!parentPtrs) {parentPtrs = [[NSSet alloc] initWithObjects:@((uintptr_t)self), nil]; } return parentPtrs;}- (void)setParentPtrs:(NSSet *)parentPtrs { objc_setAssociatedObject(self, kParentPtrsKey, parentPtrs, OBJC_ASSOCIATION_RETAIN);}

viewStack使用數組,parentPtrs使用的集合形式。都是通過運行時,用關聯對象添加屬性。

parentPtrs會在-assertNotDealloc中,會判斷當前對象是否與父節點集合有交集。下面仔細看下-assertNotDealloc方法

- (void)assertNotDealloc { //第一步 if ([MLeakedObjectProxy isAnyObjectLeakedAtPtrs:[self parentPtrs]]) {return; } //第二步 [MLeakedObjectProxy addLeakedObject:self];NSString *className = NSStringFromClass([self class]); NSLog(@'Possibly Memory Leak.nIn case that %@ should not be dealloced, override -willDealloc in %@ by returning NO.nView-ViewController stack: %@', className, className, [self viewStack]);}

1,第一步我們看到,通過parentPtrs的判斷是否有交集

產看其源碼:

+ (BOOL)isAnyObjectLeakedAtPtrs:(NSSet *)ptrs { NSAssert([NSThread isMainThread], @'Must be in main thread.'); static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{leakedObjectPtrs = [[NSMutableSet alloc] init]; }); if (!ptrs.count) {return NO } if ([leakedObjectPtrs intersectsSet:ptrs]) {return YES; } else {return NO; }}

可以看到,創建了一個單例對象,通過集合的形式,判斷是否有交集,是的話return。否則就進入第二步

2,第二步:addLeakedObject

+ (void)addLeakedObject:(id)object { NSAssert([NSThread isMainThread], @'Must be in main thread.'); MLeakedObjectProxy *proxy = [[MLeakedObjectProxy alloc] init]; proxy.object = object; proxy.objectPtr = @((uintptr_t)object); proxy.viewStack = [object viewStack]; static const void *const kLeakedObjectProxyKey = &kLeakedObjectProxyKey; objc_setAssociatedObject(object, kLeakedObjectProxyKey, proxy, OBJC_ASSOCIATION_RETAIN); [leakedObjectPtrs addObject:proxy.objectPtr];#if _INTERNAL_MLF_RC_ENABLED [MLeaksMessenger alertWithTitle:@'Memory Leak' message:[NSString stringWithFormat:@'%@', proxy.viewStack] delegate:proxy additionalButtonTitle:@'Retain Cycle'];#else [MLeaksMessenger alertWithTitle:@'Memory Leak' message:[NSString stringWithFormat:@'%@', proxy.viewStack]];#endif}

第一步:構造MLeakedObjectProxy對象,給傳入的泄漏對象 object 關聯一個代理即 proxy

第二步:通過objc_setAssociatedObject(object, kLeakedObjectProxyKey, proxy, OBJC_ASSOCIATION_RETAIN)方法,object強持有proxy, proxy若持有object,如果object釋放,proxy也會釋放

第三步:存儲 proxy.objectPtr(實際是對象地址)到集合 leakedObjectPtrs 里邊

第四步:彈框 AlertView若 _INTERNAL_MLF_RC_ENABLED == 1,則彈框會增加檢測循環引用的選項;若 _INTERNAL_MLF_RC_ENABLED == 0,則僅展示堆棧信息。

對于MLeakedObjectProxy類而言,是檢測到內存泄漏才產生的,作為泄漏對象的屬性存在的,如果泄漏的對象被釋放,那么MLeakedObjectProxy也會被釋放,則調用-dealloc函數

集合leakedObjectPtrs中移除該對象地址,同時再次彈窗,提示該對象已經釋放了

6,自己也在嘗試重寫該框架,歡迎大家一起交流

以上就是IOS內存泄漏檢查方法及重寫MLeakFinder的詳細內容,更多關于IOS內存泄漏的資料請關注好吧啦網其它相關文章!

標簽: IOS
相關文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
在线亚洲人成电影网站色www| 亚洲一区二区影院| 亚洲精品欧美综合四区| 成人妖精视频yjsp地址| 欧美伦理电影网| 亚洲超碰97人人做人人爱| 99精品国产在热久久| ㊣最新国产の精品bt伙计久久| av亚洲产国偷v产偷v自拍| 日韩欧美久久一区| 岛国精品一区二区| 日韩一区二区在线观看视频播放| 亚洲国产精品久久久久婷婷884| 一区二区三区国产盗摄| 亚洲免费毛片网站| 亚洲高清资源| 中文av一区二区| 欧美一区亚洲二区| 日韩欧美色综合网站| 国产福利电影一区二区三区| 777xxx欧美| 国产传媒日韩欧美成人| 欧美精品aⅴ在线视频| 美女精品一区二区| 欧美日韩一区小说| 久久99久久99| 91福利精品第一导航| 日韩一区欧美二区| 精品视频在线看| 国产精品18久久久久久久网站| 日韩视频免费直播| 99久久久国产精品| 欧美国产综合色视频| 国产综合18久久久久久| 亚洲男女毛片无遮挡| 日韩午夜一区| 一片黄亚洲嫩模| 免费久久99精品国产自在现线| 亚洲18色成人| 欧洲精品一区二区| 国产丶欧美丶日本不卡视频| 欧美精品一区男女天堂| 欧美成人69av| 中文字幕日韩一区二区| 亚洲二区精品| 一区二区三区高清在线| 国产精品嫩草99av在线| 亚洲综合成人在线| 色欧美片视频在线观看| 精品在线播放午夜| 欧美久久一二区| 国产·精品毛片| 久久久精品免费网站| 午夜视频一区| 国产精品久久久久婷婷二区次| 亚洲动漫精品| 亚洲电影在线播放| 色吧成人激情小说| 捆绑调教美女网站视频一区| 69堂精品视频| 99re热这里只有精品视频| 国产色综合一区| 欧美激情日韩| 亚洲色图制服丝袜| 一本一道久久综合狠狠老精东影业 | 亚洲成人免费av| 激情综合自拍| 亚洲第一成年网| 欧美日韩一区高清| 国产成人在线视频网站| 久久久午夜精品理论片中文字幕| 欧美激情亚洲| 樱花草国产18久久久久| 美女亚洲精品| 国产成人在线观看免费网站| 久久精品一区二区三区不卡| 亚洲精品孕妇| 免费精品视频最新在线| 日韩三级视频在线看| 国产字幕视频一区二区| 天天综合网天天综合色| 69堂精品视频| 欧美日韩高清在线一区| 亚洲在线视频一区| 7777女厕盗摄久久久| 欧美激情第10页| 亚洲第一会所有码转帖| 欧美日韩国产成人在线免费| 99在线精品观看| 一区二区三区在线免费播放| 欧美日韩成人综合天天影院 | 欧美午夜欧美| 三级精品在线观看| 26uuu精品一区二区在线观看| 亚洲看片免费| 国产一区三区三区| 亚洲欧洲av在线| 在线精品视频小说1| 你懂的网址国产 欧美| 一区二区理论电影在线观看| 欧美精品一二三| 91麻豆成人久久精品二区三区| 亚洲一区二区偷拍精品| 欧美精品tushy高清| 狠久久av成人天堂| 久久国产精品99久久久久久老狼 | 中文字幕日本不卡| 在线亚洲人成电影网站色www| 不卡av在线网| 亚洲国产另类av| 欧美电影免费观看高清完整版| 亚洲精品自在在线观看| 国产剧情一区二区| 亚洲精品一二三| 日韩一区二区不卡| 国产精品亚洲欧美| 成人av免费在线观看| 亚洲国产成人精品视频| 2020国产精品| 色婷婷综合久久久久中文| 9色porny自拍视频一区二区| 亚洲高清不卡在线观看| 久久理论电影网| 一本大道久久a久久精品综合| 91在线视频免费91| 麻豆成人久久精品二区三区红| 国产精品丝袜91| 欧美日韩国产电影| 亚洲一区二区三区色| 色综合久久中文字幕综合网 | 亚洲午夜精品一区二区三区他趣| 日韩免费看网站| 宅男噜噜噜66国产日韩在线观看| 成人在线视频一区| 亚洲影视资源网| 久久众筹精品私拍模特| 在线观看亚洲a| 一区二区自拍| 处破女av一区二区| 日韩成人免费电影| 亚洲欧美日韩在线| 久久久久亚洲蜜桃| 7777精品伊人久久久大香线蕉完整版 | 精品免费一区二区三区| 亚洲精品专区| 99精品久久只有精品| 激情六月婷婷久久| 亚洲国产成人va在线观看天堂| 国产人妖乱国产精品人妖| 欧美人xxxx| 国产精品一页| 欧美高清视频一区| 高清在线不卡av| 久久精品999| 午夜久久久影院| 亚洲日本青草视频在线怡红院| 日韩欧美高清在线| 欧美三级蜜桃2在线观看| 国产精品日韩二区| 黄色av日韩| 色综合久久中文字幕| 国产成人免费视频一区| 久久精品国产亚洲aⅴ| 亚洲成人tv网| 亚洲免费伊人电影| 久久蜜桃香蕉精品一区二区三区| 欧美精品久久99久久在免费线| 久久野战av| 国产精品一区亚洲| 亚洲美女啪啪| 亚洲成人在线| 红桃视频国产精品| 欧美日韩一区综合| 91日韩精品一区| 不卡高清视频专区| 岛国一区二区在线观看| 国产一区二区剧情av在线| 日本亚洲免费观看| 日韩成人精品在线| 久久国产尿小便嘘嘘尿| 五月综合激情日本mⅴ| 亚洲综合另类小说| 一区二区三区在线视频免费| 国产精品久久久久久福利一牛影视| 久久久久久久久久久久久女国产乱 | 亚洲天堂网中文字| 国产精品网友自拍| 国产校园另类小说区| 久久久亚洲国产美女国产盗摄 | 欧美aaa在线| 婷婷丁香激情综合| 日韩精品久久理论片| 婷婷六月综合网| 午夜精品久久久久久不卡8050| 亚洲图片一区二区| 亚洲一区二区精品视频| 夜夜揉揉日日人人青青一国产精品| 亚洲嫩草精品久久| 亚洲国产成人高清精品| 婷婷夜色潮精品综合在线|