日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

IOS內(nèi)存泄漏檢查方法及重寫MLeakFinder

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

對于iOS開發(fā)來講,內(nèi)存泄漏的問題,已經(jīng)是老生常談的話題。在日常的面試中經(jīng)常會提到這些問題。我們?nèi)粘5拈_發(fā)過程中進(jìn)行內(nèi)存泄漏的檢測,一般是使用instrument工具中的Leaks/Allocation來進(jìn)行排查,網(wǎng)絡(luò)上也有比較高效又好用的內(nèi)存泄漏檢測工具,MLeakFinder。

MLeakFinder-原理

首先看UIViewController,當(dāng)一個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);}

當(dāng)VC進(jìn)來的時候,添加關(guān)聯(lián)對象,并標(biāo)記為NO

2,在看viewDidAppear

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

通過代碼可以看出,獲取當(dāng)前關(guān)聯(lián)對象的標(biāo)記,當(dāng)標(biāo)記為YES的時候,就會調(diào)用willDealloc。

3,我們看什么時候會被標(biāo)記為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或者左滑返回的時候,相當(dāng)于視圖銷毀,就會被標(biāo)記為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.第一步:我們可以看到,會先判斷當(dāng)前的class是否在白名單中,是的話就會return NO,即不是內(nèi)存泄漏的。同時我們查看構(gòu)建白名單的源碼:使用了一個單例實現(xiàn),確保只有一個,是個私有方法

+ (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. 第二步:判斷該對象是否是上一次發(fā)送action的對象,是的話,不進(jìn)行內(nèi)存檢測

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

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

__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,現(xiàn)在我們回到: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調(diào)用父類的willDealloc,即上面目錄4

2,第二步:調(diào)用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]; }}

通過代碼可以看出,通過調(diào)用willReleaseChildren的方法,獲取當(dāng)前對象viewStack,parentPtrs,并且遍歷children,為每個子對象設(shè)置viewStack,parentPtrs,然后調(diào)用willDealloc。

通過源碼看一下viewStask,parentPtrs的實現(xiàn)

- (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使用數(shù)組,parentPtrs使用的集合形式。都是通過運行時,用關(guān)聯(lián)對象添加屬性。

parentPtrs會在-assertNotDealloc中,會判斷當(dāng)前對象是否與父節(jié)點集合有交集。下面仔細(xì)看下-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的判斷是否有交集

產(chǎn)看其源碼:

+ (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; }}

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

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}

第一步:構(gòu)造MLeakedObjectProxy對象,給傳入的泄漏對象 object 關(guān)聯(lián)一個代理即 proxy

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

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

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

對于MLeakedObjectProxy類而言,是檢測到內(nèi)存泄漏才產(chǎn)生的,作為泄漏對象的屬性存在的,如果泄漏的對象被釋放,那么MLeakedObjectProxy也會被釋放,則調(diào)用-dealloc函數(shù)

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

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

以上就是IOS內(nèi)存泄漏檢查方法及重寫MLeakFinder的詳細(xì)內(nèi)容,更多關(guān)于IOS內(nèi)存泄漏的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: IOS
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产一区二区三区91| 日韩欧美中文字幕电影| 综合日韩av| 一区二区三区视频免费观看| 亚洲久久一区| 日韩精品麻豆| 久久中文字幕一区二区三区| 丝袜美腿亚洲一区二区图片| 国产aⅴ精品一区二区三区久久 | 欧美亚洲免费| 久久国产小视频| 福利精品在线| 久久久久九九精品影院| 日韩精选在线| 亚洲精品第一| 亚洲影视一区二区三区| 日韩亚洲精品在线| 好吊视频一区二区三区四区| 欧美日韩一区二区综合| 吉吉日韩欧美| 特黄特色欧美大片| 麻豆视频在线看| 国产成人精品三级高清久久91| 国产日韩免费| 美女国产精品久久久| 欧美一区二区三区免费看| 中国女人久久久| 午夜日本精品| 夜久久久久久| 日本va欧美va瓶| 国产精品视频一区二区三区综合| 国产乱码精品一区二区三区亚洲人| 日韩精品免费观看视频| 亚洲综合日韩| 日韩一区二区三区高清在线观看| 日韩av一二三| 国产精品久一| 精品国产三区在线| 在线日韩电影| 免费看欧美美女黄的网站| 亚洲精品观看| 国产一区二区三区精品在线观看| 另类专区亚洲| 国产亚洲精品久久久久婷婷瑜伽| 最新国产精品久久久| 18国产精品| 欧美精品高清| 日韩欧美三区| 久久精品高清| 国产精品调教| 免费视频一区三区| 久久亚洲欧美| 日韩精品一区二区三区免费视频 | 你懂的亚洲视频| 久久伦理在线| 青青草伊人久久| 亚洲成人二区| 亚洲3区在线| 91亚洲国产成人久久精品| 国产毛片一区| 国产精品v亚洲精品v日韩精品| 欧美日韩va| 久久国产影院| 98精品久久久久久久| 91欧美极品| 日韩中文欧美在线| 色婷婷综合网| 青青国产精品| 亚洲一区二区三区高清| av资源亚洲| 国产精品天天看天天狠| 亚洲伊人影院| 美女久久久久| 色在线视频观看| 欧美日韩99| 日韩高清在线一区| 一二三区精品| 久久精品123| 日韩88av| 日本欧美国产| 成人在线视频中文字幕| 久久久精品区| 欧美黑人做爰爽爽爽| 日韩精品欧美大片| 四虎精品一区二区免费| 99国产精品| 九一成人免费视频| 久久国产中文字幕| 国内精品福利| 国产精品试看| 中文字幕av亚洲精品一部二部| 亚洲免费影院| 99国产精品久久久久久久成人热| 亚洲欧美日韩高清在线| 亚洲激情中文| 综合激情视频| 亚洲精品裸体| 麻豆久久一区| 久久天堂成人| 亚洲日本免费电影| 国产精品久久久久久久久久白浆| 麻豆精品久久| 在线成人动漫av| 美女久久久久| 国产一精品一av一免费爽爽| 免费一级欧美片在线观看网站| 激情久久一区二区| 欧美日韩免费看片| 一区在线免费| 69精品国产久热在线观看| 福利一区二区三区视频在线观看| 国产一区久久| 国产精品白浆| 欧美/亚洲一区| 日韩国产高清在线| 国产一区二区三区亚洲综合| 不卡中文一二三区| 欧美亚洲自偷自偷| 999久久久精品国产| 中文字幕亚洲在线观看| 加勒比视频一区| 日本亚洲欧美天堂免费| 福利精品一区| 日本免费一区二区视频| 亚洲1234区| 国产精品成人自拍| 亚洲欧洲一区| 91视频一区| 欧美激情aⅴ一区二区三区| 欧美日韩免费观看一区=区三区| 欧美亚洲人成在线| 免费国产自线拍一欧美视频| 久久精品理论片| 亚洲欧洲美洲国产香蕉| 亲子伦视频一区二区三区| 国产精品magnet| 蜜桃久久久久久| 91日韩在线| 欧美激情综合| 欧美日韩一区二区三区不卡视频 | 日韩综合在线| 日本va欧美va欧美va精品| 欧美日韩在线播放视频| 国产suv精品一区二区四区视频| 日韩欧美久久| 综合色一区二区| 红桃视频国产一区| 日韩欧美不卡| 国产精品久久久久久久久妇女| 欧美一区二区三区免费看| 亚洲欧美日韩国产一区| 免费av一区二区三区四区| 久久精品主播| 99热精品久久| 狠狠色狠狠色综合日日tαg| 日韩欧美国产精品综合嫩v| 国产精品久久久久久妇女| 日韩精品免费视频人成| 欧美日本一区| 久久亚洲道色| 日韩成人精品一区二区| 精品一区二区三区的国产在线观看 | 亚洲va中文在线播放免费| 人人草在线视频| 久久蜜桃资源一区二区老牛| 色爱综合网欧美| 欧美精选视频一区二区| 欧美一区二区性| 欧美专区18| 日韩av黄色在线| 国产福利一区二区三区在线播放| 国产精品一站二站| 日本午夜精品视频在线观看| 日韩1区2区日韩1区2区| 美女在线视频一区| 久久视频一区| 亚洲综合福利| 成人在线观看免费视频| 亚洲先锋成人| 综合欧美精品| 久久精品国产亚洲一区二区三区| 色偷偷偷在线视频播放| 蜜臀av国产精品久久久久 | 精品视频自拍| 伊人影院久久| 亚洲91网站| 久久久久免费| 人人爽香蕉精品| 精品国产aⅴ| 国产精品试看| 日韩精品2区| 日韩精品导航| 欧美一级精品| 麻豆精品在线| 亚洲精品人人| 欧美jjzz| 日本一区二区免费高清| 日本成人手机在线| 伊人精品一区| 日韩一区欧美|