IOS內(nèi)存泄漏檢測(cè)方式和泄漏場(chǎng)景

內(nèi)存泄漏是很常見(jiàn)的問(wèn)題冒萄,雖然在ARC后蘋果為我們解決了大量的煩惱,但是一個(gè)不小心還是會(huì)陷進(jìn)去嘱能。這段時(shí)間在公司做了一些內(nèi)存泄漏排查與修改的工作擎浴,介紹一下用到的一些檢測(cè)方式和常見(jiàn)的場(chǎng)景。


內(nèi)存泄漏的檢測(cè)方式

1. 靜態(tài)檢測(cè)

使用XCode分析功能根暑,Product->Analyze
使用靜態(tài)檢測(cè)可以檢查出一些明顯的沒(méi)有釋放的內(nèi)存力试,包括NSObject和CF開(kāi)頭的內(nèi)存泄漏,最常見(jiàn)問(wèn)題有2種排嫌,這些問(wèn)題都不復(fù)雜畸裳,需要的是細(xì)心:

  • MRC的文件,經(jīng)常遺漏release或者autorelease
  • C方式申請(qǐng)的內(nèi)存淳地,忘記釋放了
static inline NSString* iphone_device_info(){
    size_t size;
    sysctlbyname("hw.machine", NULL, &size, NULL, 0);
    char *machine = (char*)malloc(size);
    sysctlbyname("hw.machine", machine, &size, NULL, 0);
    NSString *platform = [NSString stringWithCString:machine encoding:NSASCIIStringEncoding];
    ...
}
if (alpha != 1) {
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGColorRef color = CGColorCreate(colorSpaceRef, (CGFloat[]){255, 255, 255, 0.3});
    [btn.layer setBorderColor:color];
}

不過(guò)在修改的時(shí)候需要注意:

  • 這些場(chǎng)景是否真的泄漏了怖糊,以免造成重復(fù)釋放。
  • 注意該文件是MRC還是ARC颇象,需要不同的內(nèi)存處理方式伍伤。
  • 如果是C申請(qǐng)的內(nèi)存,注意new delete遣钳, malloc free的配對(duì)處理扰魂。

比如我們的代碼中有這樣的問(wèn)題:

if ([self.itemOutput hasNewPixelBufferForItemTime:currentTime]) {
        [self displayPixelBuffer:[self.itemOutput copyPixelBufferForItemTime:currentTime itemTimeForDisplay:NULL]];
        [_program useGlProgram];
    }

在進(jìn)行靜態(tài)檢測(cè)時(shí),會(huì)報(bào)“copyPixelBufferForItemTime”內(nèi)存泄漏蕴茴,copy后的內(nèi)存需要釋放劝评。可事實(shí)上倦淀,在“displayPixelBuffer”函數(shù)中已經(jīng)對(duì)傳入對(duì)內(nèi)存進(jìn)行了釋放蒋畜,
我們姑且不論這樣對(duì)寫法是否合理,只是切記在修改時(shí)注意結(jié)合上下文處理需要釋放的內(nèi)存撞叽。

2. 動(dòng)態(tài)檢測(cè)

使用instruments百侧,這個(gè)工具網(wǎng)上的介紹比較多,可以參考如下

在Allocation中我們主要關(guān)注的是Persistent和Persistent Bytes,分別表示當(dāng)前時(shí)間段能扒,申請(qǐng)了但是還沒(méi)釋放的內(nèi)存數(shù)量和大小佣渴。
記住當(dāng)前這兩個(gè)值,然后進(jìn)入某個(gè)新頁(yè)面初斑,退出該頁(yè)面辛润,觀察這兩個(gè)值是否增加。需要注意的是,由于有些圖片調(diào)用本身是有緩存的砂竖,如果是用SDWebImage管理真椿,則網(wǎng)絡(luò)圖片都會(huì)緩存在內(nèi)存中。因此退出頁(yè)面后內(nèi)存有增加是正常的乎澄,而且還有些單例的內(nèi)存也是不會(huì)釋放的突硝,我們可以再次進(jìn)入同一個(gè)頁(yè)面,在圖片都加載過(guò)的情況下置济,反復(fù)進(jìn)入退出查看內(nèi)存狀況解恰,如果持續(xù)增加,則說(shuō)明有泄漏浙于。

3. 第三方工具MLeaksFinder

主要檢查UI方面的泄漏护盈,集成簡(jiǎn)單,在我看來(lái)主要的好處有3點(diǎn):
1.不同于instrument的分析功能羞酗,需要人工觀察腐宋,這個(gè)工具自動(dòng)檢測(cè),發(fā)現(xiàn)有泄漏后可以實(shí)時(shí)進(jìn)行提示檀轨,雖然主要是針對(duì)UI胸竞,但對(duì)于一般的工程來(lái)說(shuō),內(nèi)存泄漏的場(chǎng)景中還是以UI居多参萄,因此可以解決很大部分的問(wèn)題卫枝。
2.在新功能的開(kāi)發(fā)過(guò)程和解決bug的過(guò)程中,出現(xiàn)內(nèi)存泄漏都可以很輕松的檢測(cè)出來(lái)拧揽。
3.可以給測(cè)試同學(xué)打包時(shí)開(kāi)啟這個(gè)功能剃盾,幫助測(cè)試發(fā)現(xiàn)問(wèn)題腺占。

具體特點(diǎn)淤袜,原理和集成方式可以參考如下博客的內(nèi)容:


內(nèi)存泄漏的常見(jiàn)場(chǎng)景

CF類型內(nèi)存

注意以creat,copy作為關(guān)鍵字的函數(shù)都是需要釋放內(nèi)存的,注意配對(duì)使用衰伯。比如:CGColorCreate<-->CGColorRelease

MRC內(nèi)存使用

這部分不做詳細(xì)介紹铡羡,也是注意配對(duì)使用,需要說(shuō)明的是意鲸,如果代碼中有部分文件是MRC的烦周,在已有文件中加代碼的時(shí)候注意一下,不能都按照ARC的方式處理怎顾。

ARC內(nèi)存使用

ARC已經(jīng)為我們做了很多封裝读慎,我們不必再顯示的調(diào)用retain,release槐雾,但是還是要注意循環(huán)引用的場(chǎng)景夭委。
在此,常規(guī)的對(duì)象間的互相引用和block的循環(huán)引用大家都比較了解募强,這里就不贅述了株灸,羅列幾個(gè)我們代碼中的錯(cuò)誤崇摄。

1. NSTimer

NSTimer會(huì)造成循環(huán)引用,timer會(huì)強(qiáng)引用target即self慌烧,一般self又會(huì)持有timer作為屬性逐抑,這樣就造成了循環(huán)引用。
那么屹蚊,如果timer只作為局部變量厕氨,不把timer作為屬性呢?同樣釋放不了淑翼,因?yàn)樵诩尤雛unloop的操作中腐巢,timer被強(qiáng)引用。而timer作為局部變量玄括,是無(wú)法執(zhí)行invalidate的冯丙,所以在timer被invalidate之前,self也就不會(huì)被釋放遭京。
所以我們要注意胃惜,不僅僅是把timer當(dāng)作實(shí)例變量的時(shí)候會(huì)造成循環(huán)引用,只要申請(qǐng)了timer哪雕,加入了runloop船殉,并且target是self,雖然不是循環(huán)引用斯嚎,但是self卻沒(méi)有釋放的時(shí)機(jī)利虫。如下方式申請(qǐng)的定時(shí)器,self已經(jīng)無(wú)法釋放了堡僻。

NSTimer *timer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(commentAnimation) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

解決這種問(wèn)題有幾個(gè)實(shí)現(xiàn)方式糠惫,大家可以根據(jù)具體場(chǎng)景去選擇:

  • 增加startTimer和stopTimer方法,在合適的時(shí)機(jī)去調(diào)用钉疫,比如可以在viewDidDisappear時(shí)stopTimer硼讽,或者由這個(gè)類的調(diào)用者去設(shè)置。
  • 每次任務(wù)結(jié)束時(shí)使用dispatch_after方法做延時(shí)操作牲阁。注意使用weakself固阁,否則也會(huì)強(qiáng)引用self。
- (void)startAnimation
{
    WS(weakSelf);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [weakSelf commentAnimation];
    });
}
  • 使用GCD的定時(shí)器城菊,同樣注意使用weakself备燃。
WS(weakSelf);
timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC, 1 * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
    [weakSelf commentAnimation];
});
dispatch_resume(timer);

我的另外一篇文章對(duì)各種解決方式和其他的定時(shí)器操作做了總結(jié)(http://www.reibang.com/p/ca579c502894),大家可以參考凌唬。

2. NSNotification

使用block的方式增加notification并齐,引用了self,在刪除notification之前,self不會(huì)被釋放冀膝,與timer的場(chǎng)景類似唁奢,其實(shí)這段代碼已經(jīng)聲明了weakself,但是調(diào)用_eventManger方法還是引起了循環(huán)引用窝剖。
也就是說(shuō)麻掸,即使我們沒(méi)有調(diào)用self方法,_xxx也會(huì)造成循環(huán)引用赐纱。

[[NSNotificationCenter defaultCenter] addObserverForName:kUserSubscribeNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
    if (note) {
        Model *model=(Model *)note.object;
        if ([model.subId integerValue] == [weakSelf.subId integerValue]) {
            [_eventManger playerSubsciption:NO];
        }
    }
}

3. __block

__blockMRC中是不會(huì)增加引用的脊奋,可是在ARC中會(huì)增加,所以在ARC中疙描,只能使用__weak去打破循環(huán)引用诚隙。

__block MyViewController *weaksef = self;
_myViewController.editBlock = ^(){
    [weaksef refreshUI];
};

另外聲明一點(diǎn),并非所有的block都需要使用weak來(lái)打破循環(huán)引用起胰,如果self沒(méi)有持有block就不會(huì)造成循環(huán)引用久又。而有些地方之所以使用了__weak,是為了在[self dealloc]之后就不再執(zhí)行了效五。在這種場(chǎng)景下使用weakself時(shí)地消,也需要注意,如果self被釋放了會(huì)不會(huì)引起異常畏妖。比如下面這段代碼把weakself取到的值作為入?yún)⒙鲋矗绻鹲elf釋放了,傳nil戒劫,引起crash:

[[HttpCore sharedInstance] getRequestWithPath:url target:self params:params success:^(NSDictionary *result, NSURLRequest *request, NSHTTPURLResponse *response) {

    } failure:^(NSError *error) {
        dispatch_group_leave(weakSelf.startGroup);
    }];
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末半夷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子迅细,更是在濱河造成了極大的恐慌巫橄,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疯攒,死亡現(xiàn)場(chǎng)離奇詭異嗦随,居然都是意外死亡列荔,警方通過(guò)查閱死者的電腦和手機(jī)敬尺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)贴浙,“玉大人砂吞,你說(shuō)我怎么就攤上這事∑槔#” “怎么了蜻直?”我有些...
    開(kāi)封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我概而,道長(zhǎng)呼巷,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任赎瑰,我火速辦了婚禮王悍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘餐曼。我一直安慰自己压储,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布源譬。 她就那樣靜靜地躺著集惋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪踩娘。 梳的紋絲不亂的頭發(fā)上刮刑,一...
    開(kāi)封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天,我揣著相機(jī)與錄音养渴,去河邊找鬼为朋。 笑死,一個(gè)胖子當(dāng)著我的面吹牛厚脉,可吹牛的內(nèi)容都是我干的习寸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼傻工,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼霞溪!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起中捆,我...
    開(kāi)封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鸯匹,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后泄伪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體殴蓬,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年蟋滴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了染厅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡津函,死狀恐怖肖粮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情尔苦,我是刑警寧澤涩馆,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布行施,位于F島的核電站,受9級(jí)特大地震影響魂那,放射性物質(zhì)發(fā)生泄漏蛾号。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一涯雅、第九天 我趴在偏房一處隱蔽的房頂上張望须教。 院中可真熱鬧,春花似錦斩芭、人聲如沸轻腺。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)贬养。三九已至,卻和暖如春琴庵,著一層夾襖步出監(jiān)牢的瞬間误算,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工迷殿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留儿礼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓庆寺,卻偏偏與公主長(zhǎng)得像蚊夫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子懦尝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 內(nèi)存泄漏的相關(guān)定義 OC當(dāng)中內(nèi)存管理方式:ARC/MRCARC:自動(dòng)引用計(jì)數(shù)(系統(tǒng)自動(dòng)管理內(nèi)存)知纷,由開(kāi)發(fā)人員開(kāi)辟內(nèi)...
    騎老虎喊救命閱讀 3,135評(píng)論 0 2
  • 內(nèi)存管理 簡(jiǎn)述OC中內(nèi)存管理機(jī)制。與retain配對(duì)使用的方法是dealloc還是release陵霉,為什么琅轧?需要與a...
    丶逐漸閱讀 1,964評(píng)論 1 16
  • 前言 內(nèi)存泄露是一個(gè)相對(duì)挺嚴(yán)重的問(wèn)題,可是它的存在未引起足夠的重視踊挠,如果程序運(yùn)行時(shí)一直分配內(nèi)存而不及時(shí)釋放無(wú)用的內(nèi)...
    進(jìn)無(wú)盡閱讀 1,791評(píng)論 0 5
  • 為自己學(xué)習(xí)方便乍桂,復(fù)制大神的學(xué)習(xí)性文章放在自己簡(jiǎn)書里,僅作為學(xué)習(xí)方便使用效床,如果作者疑此行為侵權(quán)睹酌,請(qǐng)隨時(shí)聯(lián)系本人刪除,...
    天地不仁以萬(wàn)物為芻狗閱讀 4,904評(píng)論 2 3
  • 前陣子給父母打電話闯传,電話那頭響了很久才接谨朝。父母什么時(shí)候?qū)⒆拥碾娫掃@么沒(méi)有期待了卤妒? -“媽,你做什么去了字币,這才九點(diǎn)...
    WhatYouSay橙子醬閱讀 5,260評(píng)論 0 1