精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

iOS內功篇:內存管理

移動開發
內存管理是程序設計中很重要的一部分,程序在運行的過程中消耗內存,運行結束后釋放占用的內存。如果程序運行時一直分配內存而不及時釋放無用的內存,會造成這樣的后果:程序占用的內存越來越大,直至內存消耗殫盡,程序因無內存可用導致崩潰,這樣的情況我們稱之為內存泄漏。

[[165151]]

前言

現在iOS開發已經是arc甚至是swift的時代,但是內存管理仍是一個重點關注的問題,如果只知盲目開發而不知個中原理,踩坑就跳不出來了,理解好內存管理,能讓我們寫出更有質量的代碼。

內存管理是程序設計中很重要的一部分,程序在運行的過程中消耗內存,運行結束后釋放占用的內存。如果程序運行時一直分配內存而不及時釋放無用的內存,會造成這樣的后果:程序占用的內存越來越大,直至內存消耗殫盡,程序因無內存可用導致崩潰,這樣的情況我們稱之為內存泄漏。

ObjC的內存管理比較簡潔,然而要深刻理解也不是一件易事,本文將介紹如何使用ObjC進行內存管理。

1、引用計數

在ObjC中,對象什么時候會被釋放(或者對象占用的內存什么時候會被回收利用)?

答案是:當對象沒有被任何變量引用(也可以說是沒有指針指向該對象)的時候,就會被釋放。

那怎么知道對象已經沒有被引用了呢?

ObjC采用引用計數(reference counting)的技術來進行管理:

1)每個對象都有一個關聯的整數,稱為引用計數器

2)當代碼需要使用該對象時,則將對象的引用計數加1

3)當代碼結束使用該對象時,則將對象的引用計數減1

4)當引用計數的值變為0時,表示對象沒有被任何代碼使用,此時對象將被釋放。

與之對應的消息發送方法如下:

1)當對象被創建(通過alloc、new或copy等方法)時,其引用計數初始值為1

2)給對象發送retain消息,其引用計數加1

3)給對象發送release消息,其引用計數減1

4)當對象引用計數歸0時,ObjC給對象發送dealloc消息銷毀對象

下面通過一個簡單的例子來說明:

場景:有一個寵物中心(內存),可以派出小動物(對象)陪小朋友們玩耍(對象引用者),現在xiaoming想和小狗一起玩耍。

新建Dog類,重寫其創建和銷毀的方法:

  1. @implementation Dog 
  2.   
  3.     - (instancetype)init { 
  4.         if (self = [super init]) { 
  5.             NSLog(@"小狗被派出去啦!初始引用計數為 %ld",self.retainCount); 
  6.         } 
  7.         return self; 
  8.     } 
  9.   
  10.     - (void)dealloc { 
  11.         NSLog(@"小狗回到寵物中心"); 
  12.         [super dealloc]; 
  13.     } 
  14. @end 

在main方法中創建dog對象,給dog發送消息

  1. //模擬:寵物中心派出小狗 
  2. Dog * dog = [[Dog alloc]init]; 
  3. //模擬:xiaoming需要和小狗玩耍,需要將其引用計數加1 
  4. [dog retain]; 
  5. NSLog(@"小狗的引用計數為 %ld",dog.retainCount); 
  6. //模擬:xiaoming不和小狗玩耍了,需要將其引用計數減1 
  7. [dog release]; 
  8. NSLog(@"小狗的引用計數為 %ld",dog.retainCount); 
  9. //沒人需要和小狗玩耍了,將其引用計數減1 
  10. [dog release]; 
  11. //將指針置nil,否則變為野指針 
  12. dog = nil; 

輸出結果為

  1. [34691:7638855] 初始引用計數為 1 
  2. [34691:7638855] 小狗的引用計數為 2 
  3. [34691:7638855] 小狗的引用計數為 1 
  4. [34691:7638855] 銷毀Dog 

可以看到,引用計數幫助寵物中心很好的標記了小狗的使用狀態,在完成任務的時候及時收回到寵物中心。

思考幾個問題:

1)NSString引用計數問題

如果我們嘗試查看一個string的引用計數

  1. NSString * str = @"hello guys"
  2. NSLog(@"%ld", str.retainCount); 

會發現引用計數為-1,這可以理解為NSString實際上是一個字符串常量,是沒有引用計數的(或者它的引用計數是一個很大的值(使用%lu可以打印查看),對它做引用計數操作沒實質上的影響)。

2)賦值不會擁有某個對象

  1. NSString * name = dog.name; 

這里僅僅是指針賦值操作,并不會增加name的引用計數,需要持有對象必須要發送retain消息。

3)dealloc

由于釋放對象是會調用dealloc方法,因此重寫dealloc方法來查看對象釋放的情況,如果沒有調用則會造成內存泄露。在上面的例子中我們通過重寫dealloc讓小狗被釋放的時候打印日志來告訴我們已經完成釋放。

4)在上面例子中,如果我們增加這樣一個操作

  1. //沒人需要和小狗玩耍了,將其引用計數減1 
  2. [dog release]; 
  3. NSLog(@"%ld",dog.retainCount); 

會發現獲取到的引用計數為1,為什么不是0呢?

這是因為對引用計數為1的對象release時,系統知道該對象將被回收,就不會再對該對象的引用計數進行減1操作,這樣可以增加對象回收的效率。

另外,對已釋放的對象發送消息是不可取的,因為對象的內存已被回收,如果發送消息時,該內存已經被其他對象使用了,得到的結果是無法確定的,甚至會造成崩潰。

2、自動釋放池

現在已經明確了,當不再使用一個對象時應該將其釋放,但是在某些情況下,我們很難理清一個對象什么時候不再使用(比如xiaoming和小狗玩耍結束的時間不確定),這可怎么辦?

ObjC提供autorelease方法來解決這個問題,當給一個對象發送autorelease消息時,方法會在未來某個時間給這個對象發送release消息將其釋放,在這個時間段內,對象還是可以使用的。

那autorelease的原理是什么呢?

原理就是對象接收到autorelease消息時,它會被添加到了當前的自動釋放池中,當自動釋放池被銷毀時,會給池里所有的對象發送release消息。

這里就引出了自動釋放池這個概念,什么是自動釋放池呢? 顧名思義,就是一個池,這個池可以容納對象,而且可以自動釋放,這就大大增加了我們處理對象的靈活性。

自動釋放池怎樣創建?

ObjC提供兩種方法創建自動釋放池:

方法一:使用NSAutoreleasePool來創建

  1. NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init]; 
  2. //這里寫代碼 
  3. [pool release]; 

方法二:使用@autoreleasepool創建

  1. @autoreleasepool { 
  2.     //這里寫代碼 

自動釋放池創建后,就會成為活動的池子,釋放池子后,池子將釋放其所包含的所有對象。

以上兩種方法推薦***種,因為將內存交給ObjC管理更高效。

自動釋放池什么時候創建?

app使用過程中,會定期自動生成和銷毀自動釋放池,一般是在程序事件處理之前創建,當然我們也可以自行創建自動釋放池,來達到我們一些特定的目的。

自動釋放池什么時候銷毀?

自動釋放池的銷毀時間是確定的,一般是在程序事件處理之后釋放,或者由我們自己手動釋放。

下面舉例說明自動釋放池的工作流程:

場景:現在xiaoming和xiaohong都想和小狗一起玩耍,但是他們的需求不一樣,他們的玩耍時間不一樣,流程如下

  1. //創建一個自動釋放池 
  2. NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 
  3. //模擬:寵物中心派出小狗 
  4. Dog * dog = [[Dog alloc]init]; 
  5. //模擬:xiaoming需要和小狗玩耍,需要將其引用計數加1 
  6. [dog retain]; 
  7. NSLog(@"小狗的引用計數為 %ld",dog.retainCount); 
  8. //模擬:xiaohong需要和小狗玩耍,需要將其引用計數加1 
  9. [dog retain]; 
  10. NSLog(@"小狗的引用計數為 %ld",dog.retainCount); 
  11. //模擬:xiaoming確定不想和小狗玩耍了,需要將其引用計數減1 
  12. [dog release]; 
  13. NSLog(@"小狗的引用計數為 %ld",dog.retainCount); 
  14. //模擬:xiaohong不確定何時不想和小狗玩耍了,將其設置為自動釋放 
  15. [dog autorelease]; 
  16. NSLog(@"小狗的引用計數為 %ld",dog.retainCount); 
  17. //沒人需要和小狗玩耍了,將其引用計數減1 
  18. [dog release]; 
  19. NSLog(@"釋放池子"); 
  20. [pool release]; 
  21. //創建一個自動釋放池 
  22. @autoreleasepool { 
  23.     //模擬:寵物中心派出小狗 
  24.     Dog * dog = [[Dog alloc]init]; 
  25.     //模擬:xiaoming需要和小狗玩耍,需要將其引用計數加1 
  26.     [dog retain]; 
  27.     NSLog(@"小狗的引用計數為 %ld",dog.retainCount); 
  28.     //模擬:xiaohong需要和小狗玩耍,需要將其引用計數加1 
  29.     [dog retain]; 
  30.     NSLog(@"小狗的引用計數為 %ld",dog.retainCount); 
  31.     //模擬:xiaoming確定不想和小狗玩耍了,需要將其引用計數減1 
  32.     [dog release]; 
  33.     NSLog(@"小狗的引用計數為 %ld",dog.retainCount); 
  34.     //模擬:xiaohong不確定何時不想和小狗玩耍了,將其設置為自動釋放 
  35.     [dog autorelease]; 
  36.     NSLog(@"小狗的引用計數為 %ld",dog.retainCount); 
  37.     //沒人需要和小狗玩耍了,將其引用計數減1 
  38.     [dog release]; 
  39.     NSLog(@"釋放池子"); 

輸出結果如下:

  1. [34819:7801589] 初始引用計數為 1 
  2. [34819:7801589] 小狗的引用計數為 2 
  3. [34819:7801589] 小狗的引用計數為 3 
  4. [34819:7801589] 小狗的引用計數為 2 
  5. [34819:7801589] 小狗的引用計數為 2 
  6. [34819:7801589] 釋放池子 
  7. [34819:7801589] 銷毀Dog 

可以看到,當池子釋放后,dog對象才被釋放,因此在池子釋放之前,xiaohong都可以盡情地和小狗玩耍。

使用自動釋放池需要注意:

1)自動釋放池實質上只是在釋放的時候給池中所有對象對象發送release消息,不保證對象一定會銷毀,如果自動釋放池向對象發送release消息后對象的引用計數仍大于1,對象就無法銷毀。

2)自動釋放池中的對象會集中同一時間釋放,如果操作需要生成的對象較多占用內存空間大,可以使用多個釋放池來進行優化。比如在一個循環中需要創建大量的臨時變量,可以創建內部的池子來降低內存占用峰值。

3)autorelease不會改變對象的引用計數

自動釋放池的常見問題:

在管理對象釋放的問題上,自動幫助我們釋放池節省了大量的時間,但是有時候它卻未必會達到我們期望的效果,比如在一個循環事件中,如果循環次數較大或者事件處理占用內存較大,就會導致內存占用不斷增長,可能會導致不希望看到的后果。

示例代碼:

  1. for (int i = 0; i < 100000; i ++) { 
  2.     NSString * log  = [NSString stringWithFormat:@"%d", i]; 
  3.     NSLog(@"%@", log); 

前面講過,自動釋放池的釋放時間是確定的,這個例子中自動釋放池會在循環事件結束時釋放,那問題來了:在這個十萬次的循環中,每次都會生成一個字符串并打印,這些字符串對象都放在池子中并直到循環結束才會釋放,因此在循環期間內存不增長。

這類問題的解決方案是在循環中創建新的自動釋放池,多少個循環釋放一次由我們自行決定。

  1. for (int i = 0; i < 100000; i ++) { 
  2.     @autoreleasepool { 
  3.         NSString * log  = [NSString stringWithFormat:@"%d", i]; 
  4.         NSLog(@"%@", log); 
  5.     } 

3、iOS的內存管理規則

3.1 基本原則

無規矩不成方圓,在iOS開發中也存在規則來約束開發者進行內存管理,總的來講有三點:

1)當你通過new、alloc或copy方法創建一個對象時,它的引用計數為1,當不再使用該對象時,應該向對象發送release或者autorelease消息釋放對象。

2)當你通過其他方法獲得一個對象時,如果對象引用計數為1且被設置為autorelease,則不需要執行任何釋放對象的操作;

3)如果你打算取得對象所有權,就需要保留對象并在操作完成之后釋放,且必須保證retain和release的次數對等。

應用到文章開頭的例子中,小朋友每申請一個小狗(生成對象),***都要歸還到寵物中心(釋放對象),如果只申請而不歸還(對象創建了沒有釋放),那寵物中心的小狗就會越來越少(可用內存越來越少),到***一個小狗都沒有了(內存被耗盡),其他小朋友就再也沒有小狗可申請了(無資源可申請使用),因此,必須要遵守規則:申請必須歸還(規則1),申請幾個必須歸還幾個(規則3),如果小狗被設定歸還時間則不用小朋友主動歸還(規則2)。

有興趣的讀者可以思考:

以上原則可以總結成一句簡潔的話,是什么呢?

3.2 ARC

在MRC時代,必須嚴格遵守以上規則,否則內存問題將成為惡魔一樣的存在,然而來到ARC時代,事情似乎變得輕松了,不用再寫無止盡的ratain和release似乎讓開發變得輕松了,對初學者變得更友好。

ObjC2.0引入了垃圾回收機制,然而由于垃圾回收機制會對移動設備產生某些不好的影響(例如由于垃圾清理造成的卡頓),iOS并不支持這個機制,蘋果的解決方案就是ARC(自動引用計數)。

iOS5以后,我們可以開啟ARC模式,ARC可以理解成一位管家,這個管家會幫我們向對象發送retain和release語句,不再需要我們手動添加了,我們可以更舒心地創建或引用對象,簡化內存管理步驟,節省大量的開發時間。

實際上,ARC不是垃圾回收,也并不是不需要內存管理了,它是隱式的內存管理,編譯器在編譯的時候會在代碼插入合適的ratain和release語句,相當于在背后幫我們完成了內存管理的工作。

下面將自動釋放池的例子轉化成ARC來看看

  1. @autoreleasepool { 
  2.     Dog * dog = [[Dog alloc]init]; 
  3.     [xiaoming playWithDog:dog]; 
  4.     [xiaohong playWithDog:dog]; 
  5.     NSLog(@"釋放池子"); 

怎么樣,是不是簡潔了很多,是不是很熟悉的感覺呢。

注意:

1)如果你的工程歷史比較久,可以將其從MRC轉換成ARC,跟上時代的步伐更好地維護

2)如果你的工程引用了某些不支持ARC的庫,可以在Build Phases的Compile Sources將對應的m文件的編譯器參數配置為-fno-objc-arc

3)ARC能幫我們簡化內存管理問題,但不代表它是***的,還是有它不能處理的情況,這就需要我們自己手動處理,比如循環引用、非ObjC對象、Core Foundation中的malloc()或者free()等等

有興趣的讀者可以思考:

MRC有什么缺點?ARC有什么局限性?請列舉。

3.3 ARC的修飾符

ARC提供四種修飾符,分別是strong, weak, autoreleasing, unsafe_unretained。

__strong:強引用,持有所指向對象的所有權,無修飾符情況下的默認值。如需強制釋放,可置nil。

比如我們常用的定時器

  1. NSTimer * timer = [NSTimer timerWith...]; 

相當于

  1. NSTimer * __strong timer = [NSTimer timerWith...]; 

當不需要使用時,強制銷毀定時器

  1. [timer invalidate]; 
  2. timer = nil; 

__weak:弱引用,不持有所指向對象的所有權,引用指向的對象內存被回收之后,引用本身會置nil,避免野指針。

比如避免循環引用的弱引用聲明:

  1. __weak __typeof(self) weakSelf = self; 

__autoreleasing:自動釋放對象的引用,一般用于傳遞參數

比如一個讀取數據的方法

  1. - (void)loadData:(NSError **)error; 

當你調用時會發現這樣的提示

  1. NSError * error; 
  2. [dataTool loadData:(NSError *__autoreleasing *)] 

這是編譯器自動幫我們插入以下代碼

  1. NSError * error; 
  2. NSError * __autoreleasing tmpErr = error; 
  3. [dataTool loadData:&tmpErr]; 

__unsafe_unretained:為兼容iOS5以下版本的產物,可以理解成MRC下的weak,現在基本用不到,這里不作描述。

有興趣的讀者可以思考:

1)__strong NSTimer * timer 和 NSTimer * __strong timer哪個寫法是正確的, 為什么編譯器不報錯?

2)使用__autoreleasing可能會遇到哪些問題?

3.4 屬性的內存管理

ObjC2.0引入了@property,提供成員變量訪問方法、權限、環境、內存管理類型的聲明,下面主要說明ARC中屬性的內存管理。

屬性的參數分為三類,基本數據類型默認為(atomic,readwrite,assign),對象類型默認為(atomic,readwrite,strong),其中第三個參數就是該屬性的內存管理方式修飾,修飾詞可以是以下之一:

1)assign:直接賦值

assign一般用來修飾基本數據類型

@property (nonatomic, assign) NSInteger count;

當然也可以修飾ObjC對象,但是不推薦,因為被assign修飾的對象釋放后,指針還是指向釋放前的內存,在后續操作中可能會導致內存問題引發崩潰。

2)retain:release舊值,再retain新值(引用計數+1)

retain和strong一樣,都用來修飾ObjC對象。

使用set方法賦值時,實質上是會先保留新值,再釋放舊值,再設置新值,避免新舊值一樣時導致對象被釋放的的問題。

MRC寫法如下

  1. - (void)setCount:(NSObject *)count { 
  2.     [count retain]; 
  3.     [_count release]; 
  4.     _count = count; 

ARC對應寫法

  1. - (void)setCount:(NSObject *)count { 
  2.     _count = count; 

3)copy:release舊值,再copy新值(拷貝內容)

一般用來修飾String、Dict、Array等需要保護其封裝性的對象,尤其是在其內容可變的情況下,因此會拷貝(深拷貝)一份內容給屬性使用,避免可能造成的對源內容進行改動。

使用set方法賦值時,實質上是會先拷貝新值,再釋放舊值,再設置新值。

實際上,遵守NSCopying的對象都可以使用copy,當然,如果你確定是要共用同一份可變內容,你也可以使用strong或retain。

@property (nonatomic, copy) NSString * name;

4)weak:ARC新引入修飾詞,可代替assign,比assign多增加一個特性(置nil,見上文)。

weak和strong一樣用來修飾ObjC對象。

使用set方法賦值時,實質上不保留新值,也不釋放舊值,只設置新值。

比如常用的代理的聲明

  1. @property (weak) id<mydelegate> delegate;</mydelegate> 

Xib控件的引用

  1. @property (weak, nonatomic) IBOutlet UIImageView *productImage; 

5)strong:ARC新引入修飾詞,可代替retain

可參照retain,這里不再作描述。

有興趣的讀者可以思考:

1)各個屬性修飾詞和3.3中的修飾詞的對應關系?

2)屬性的本質是什么?

3.5 block的內存管理

iOS中使用block必須自己管理內存,錯誤的內存管理將導致循環引用等內存泄漏問題,這里主要說明在ARC下block聲明和使用的時候需要注意的兩點:

1)如果你使用@property去聲明一個block的時候,一般使用copy來進行修飾(當然也可以不寫,編譯器自動進行copy操作),盡量不要使用retain。

@property (nonatomic, copy) void(^block)(NSData * data);

2)block會對內部使用的對象進行強引用,因此在使用的時候應該確定不會引起循環引用,當然保險的做法就是添加弱引用標記。

__weak typeof(self) weakSelf = self;

有興趣的讀者可以深入了解:

1、block的內部實現原理是什么?

2、從內存位置來看block有幾種類型?它們的內存管理方式各是怎樣的?

3、對于不同類型的外部變量,block的內存管理都是怎樣的?

4 經典內存泄漏及其解決方案

雖然ARC好處多多,然而也并無法避免內存泄漏問題,下面介紹在ARC中常見的內存泄漏。

4.1 僵尸對象和野指針

僵尸對象:內存已經被回收的對象。

野指針:指向僵尸對象的指針,向野指針發送消息會導致崩潰。

野指針錯誤形式在Xcode中通常表現為:Thread 1:EXC_BAD_ACCESS,因為你訪問了一塊已經不屬于你的內存。

例子代碼:(沒有出現錯誤的筒子多運行幾遍,因為獲取野指針指向的結果是不確定的)

  1. Dog * dog = [[Dog alloc]init]; 
  2. NSLog(@"before"); 
  3. NSLog(@"%s",object_getClassName(dog)); 
  4. [dog release]; 
  5. NSLog(@"after"); 
  6. NSLog(@"%s",object_getClassName(dog)); 

運行結果:

  1. [15184:5811062] before 
  2. [15184:5811062] Dog 
  3. [15184:5811062] after 
  4. (lldb) 

可以看到,當運行到第六行的時候崩潰了,并給出了EXC_BAD_ACCESS的提示。

解決方案:

對象已經被釋放后,應將其指針置為空指針(沒有指向任何對象的指針,給空指針發送消息不會報錯)。

然而在實際開發中實際遇到EXC_BAD_ACCESS錯誤時,往往很難定位到錯誤點,幸好Xcode提供方便的工具給我們來定位及分析錯誤。

1)在product-scheme-edit scheme-diagnostics中將enable zombie objects勾選上,下次再出現這樣的錯誤就可以準確定位了。

運行結果:

  1. [15169:5801945] before 
  2. [15169:5801945] Dog 
  3. [15169:5801945] after 
  4. [15169:5801945] _NSZombie_Dog 

可以看到,當運行到第六行時并沒有崩潰,并給出了NSZombie的提示。

2)在Xcode-open developer tool-Instruments打開工具集,選擇Zombies工具可以對已安裝的應用進行僵尸對象檢測。

4.2 循環引用

循環引用是ARC中最常出現的問題,對于可能引發循環引用的一些原因在前一篇文章iOS總結篇:影響控制器正常釋放的常見問題中有提及,大家可以看看。

一般來講循環引用也是可以使用工具來檢測到的,分為兩種:

1)在product-Analyze中使用靜態分析來檢測代碼中可能存在循環引用的問題。

2)在Xcode-open developer tool-Instruments打開工具集,選擇Leaks工具可以對已安裝的應用進行內存泄漏檢測,此工具能檢測靜態分析不會提示,但是到運行時才會出現的內存泄漏問題。

Leaks工具雖然強大,但是它不能檢測到block循環引用導致的內存泄漏,這種情況一般需要自行排查問題(考驗你的基本功時候到了),傻瓜式的方案當然是重寫對象的dealloc方法來監測對象是否正常釋放,來確認沒有形成循環引用。

由于ARC中循環引用出現的幾率相對較大,很多大神或者團隊都提供了很多解決此問題的思路和方法,甚至開發了插件和類庫來幫助開發者更好地檢測問題,有興趣的讀者可以研究一下,是否好用,孰好孰壞就由讀者自行評判了。

4.3 循環中對象占用內存大

這個問題常見于循環次數較大,循環體生成的對象占用內存較大的情景。

例子代碼:我需要10000個演員來打仗

  1. for (int i = 0; i < 10000; i ++) { 
  2.     Person * soldier = [[Person alloc]init]; 
  3.     [soldier fight]; 

該循環內產生大量的臨時對象,直至循環結束才釋放,可能導致內存泄漏,解決方法和上文中提到的自動釋放池常見問題類似:在循環中創建自己的autoReleasePool,及時釋放占用內存大的臨時變量,減少內存占用峰值。

  1. for (int i = 0; i < 10000; i ++) { 
  2.     @autoreleasepool { 
  3.     Person * soldier = [[Person alloc]init]; 
  4.     [soldier fight]; 
  5.     } 

然而有時候autoReleasePool也不是***的:

例子:假如有2000張圖片,每張1M左右,現在需要獲取所有圖片的尺寸,你會怎么做?

如果這樣做

  1. for (int i = 0; i < 2000; i ++) { 
  2.     CGSize size = [UIImage imageNamed:[NSString stringWithFormat:@"%d.jpg",i]].size; 
  3.     //add size to array 

用imageNamed方法加載圖片占用Cache的內存,autoReleasePool也不能釋放,對此問題需要另外的解決方法,當然保險的當然是雙管齊下了

  1. for (int i = 0; i < 2000; i ++) { 
  2.         @autoreleasepool { 
  3.         CGSize size = [UIImage imageWithContentsOfFile:filePath].size; 
  4.         //add siez to array 
  5.     } 

4.4 ***循環

這個是比4.3更極端的情況,無論你出于什么原因,當你啟動了一個***循環的時候,ARC會默認該方法用不會執行完畢,方法里面的對象就永不釋放,內存***上漲,導致內存泄漏。

例子:

  1. NSLog(@"start !"); 
  2. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
  3.         BOOL isSucc = YES; 
  4.         while (isSucc) { 
  5.         [NSThread sleepForTimeInterval:1.0]; 
  6.         NSLog(@"create an obj"); 
  7.     } 
  8. }); 

輸出結果為

  1. [7026:3555827] start ! 
  2. [7026:3556236] create an obj 
  3. [7026:3556236] create an obj 
  4. [7026:3556236] create an obj 
  5. [7026:3556236] create an obj 
  6. [7026:3555827] dealloc 
  7. [7026:3556236] create an obj 
  8. [7026:3556236] create an obj 
  9. [7026:3556236] create an obj 

可以看到,當控制器釋放后該循環還在繼續。

對于這類問題解決方案是什么呢?留給讀者思考吧~ ^_^

提示:解決方法有autoreleasepool、block、timer等等

后記

關于iOS內存管理的知識點很多,如果展開來講,本文涉及的知識點都可以寫成一篇長文,因此,本文只是做一個概述,試圖起到拋磚引玉的作用,幫助iOS開發的初學者更快地理解內存管理。

關于第四點“經典內存泄漏及其解決方案”,將專門寫一篇文章在本文的基礎上詳細介紹(圖文并茂),敬請期待。

責任編輯:倪明 來源: 明仔Su的簡書
相關推薦

2018-07-23 09:26:08

iOS內存優化

2017-03-07 10:15:35

iOS內存管理開發

2017-09-13 10:51:25

技術人基礎知識互聯網技術

2017-02-09 21:24:22

iOS內存管理

2011-07-21 14:42:45

iOS UIViewCont 內存

2015-03-13 09:30:23

iOS內存管理

2015-06-25 09:47:20

iOS內存管理

2011-02-22 14:47:52

SQL Server資

2011-02-28 08:57:10

SQL Server資內存性能調優

2014-03-12 09:37:22

內存管理autoreleaseautorelease

2012-06-20 13:54:44

架構性能優化

2019-07-09 14:17:28

Linux內存管理進程

2011-07-21 17:40:43

iOS 多核 內存

2011-08-05 16:41:48

iOS 隊列 內存

2016-03-03 10:07:39

ios內存管理面試總結

2020-09-17 11:19:39

Linux 系統 數據

2011-08-22 11:07:16

IOS 開發多核內存

2021-10-18 10:54:48

.NET內存管理

2010-12-22 13:14:52

Linux性能監測

2013-07-19 13:16:26

iOS中BlockiOS開發學習內存管理
點贊
收藏

51CTO技術棧公眾號

欧美激情图片小说| 日本中文字幕影院| 你懂的在线视频| 欧美亚洲视频| xxx一区二区| 亚洲成年人av| 久久av日韩| 亚洲国产另类av| 亚洲欧美日韩不卡一区二区三区| 国产xxxx孕妇| 日日夜夜精品视频免费| 欧美成人午夜激情在线| 蜜桃av免费看| 亚洲日本va午夜在线电影| 在线欧美一区二区| 久久国产精品视频在线观看| 日本在线免费看| 99精品1区2区| 97超碰最新| 一级欧美一级日韩| 午夜亚洲影视| 欧美激情图片区| 99热6这里只有精品| 欧美交a欧美精品喷水| 日韩一二三区不卡| 亚洲精品高清无码视频| 国产99在线观看| 亚洲精品伦理在线| 午夜老司机精品| 人成免费电影一二三区在线观看| 国产精品88av| 成人久久一区二区| 最新在线中文字幕| 丝瓜av网站精品一区二区| 久久久亚洲国产天美传媒修理工| 日韩在线视频网址| 成人直播大秀| 国产亚洲精品美女久久久| 精品人妻伦一二三区久| 人人九九精品视频| 91精品国产综合久久婷婷香蕉| 色哟哟精品视频| 桃花岛成人影院| 精品国产91久久久久久| 精品国偷自产一区二区三区| av电影高清在线观看| 国产精品嫩草影院com| 日韩高清av电影| 黄色毛片在线观看| 国产亚洲综合色| 日韩av大全| av大片在线观看| 国产精品污污网站在线观看| 亚洲国产日韩综合一区| 1区2区3区在线观看| 国产欧美视频一区二区三区| 蜜桃麻豆91| 久久99久久| 欧美高清在线一区| 在线综合视频网站| 成人看片免费| 亚洲综合免费观看高清完整版在线 | 一区二区三区四区欧美| 免费a级人成a大片在线观看| 国产精品久99| 国产成人三级视频| 日本精品600av| 亚洲成av人片在www色猫咪| 狠狠97人人婷婷五月| xx欧美视频| 欧美中文字幕一区二区三区| 久久久久久久久久一区二区| 欧美第一在线视频| 亚洲电影av在线| 久久亚洲AV成人无码国产野外| 久久不见久久见免费视频7| 中国人与牲禽动交精品| 国产精品三区在线观看| 激情综合视频| 国产精品99免视看9| 国产日韩免费视频| 不卡一区在线观看| 日韩久久久久久久| 国产激情视频在线| 午夜电影一区二区三区| 黄色三级视频片| 日韩欧美一级| 国产一区二区三区在线| 欧美黄色aaa| 一区二区三区精品视频在线观看| 国产精品黄色av| 国产内射老熟女aaaa∵| 97久久精品人人爽人人爽蜜臀| 欧美少妇一区| 18videosex性欧美麻豆| 欧美三级免费观看| 日日夜夜精品视频免费观看| 香蕉久久夜色精品国产更新时间| 日韩亚洲欧美中文高清在线| 国产午夜视频在线| 久久国产生活片100| 精品视频一区在线| 久cao在线| 色婷婷久久久综合中文字幕| 亚洲一区和二区| 久久一区二区三区电影| 68精品国产免费久久久久久婷婷| 91 中文字幕| 久久先锋影音av鲁色资源网| 黄色成人在线免费观看| 国产第一亚洲| 日韩精品电影网| 国产在线综合网| 激情综合色综合久久综合| 欧美日韩中文国产一区发布| 182在线播放| 欧美一区二区三区白人| 美女av免费看| 日日夜夜精品视频免费| 久久香蕉综合色| 金瓶狂野欧美性猛交xxxx| 欧美日韩成人综合在线一区二区| 亚洲中文字幕无码av| 女人色偷偷aa久久天堂| 成人久久一区二区三区| 日日夜夜精品一区| 欧美性做爰猛烈叫床潮| 中文字幕高清视频| 亚洲三级国产| 国产嫩草一区二区三区在线观看| av软件在线观看| 欧美日高清视频| 在线观看免费小视频| 裸体一区二区| 欧美日韩电影一区二区三区| 精品人人视频| 精品久久久久久久一区二区蜜臀| 欧美一区二区三区爽爽爽| 极品少妇xxxx偷拍精品少妇| 一区二区av| 欧美网站免费| 日韩在线视频一区| 国产精品一区二区黑人巨大| 亚洲色欲色欲www在线观看| 性欧美1819| 四季av在线一区二区三区| 国产美女主播一区| 欧洲不卡av| 欧美一区二区三区在线观看| 26uuu成人网| 国产高清不卡一区| 日本一本中文字幕| 欧美wwwwww| 欧美在线视频网站| 国产香蕉在线| 欧美三级在线看| 天天做夜夜爱爱爱| 国产精品影视在线观看| 国产一区二区片| 噜噜噜狠狠夜夜躁精品仙踪林| 韩国美女主播一区| 九色国产在线观看| 欧美三级日韩三级国产三级| 亚洲精品久久久久久国| 国产成人免费视频一区| 青青青青草视频| 天天躁日日躁狠狠躁欧美巨大小说| 欧美专区中文字幕| 大胆av不用播放器在线播放| 欧美高清视频www夜色资源网| wwwav国产| youjizz国产精品| 欧美 日韩精品| 91亚洲国产| 福利精品视频| 欧美电影网站| 久久亚洲电影天堂| av女名字大全列表| 精品视频在线免费观看| 动漫性做爰视频| 91在线高清观看| 亚洲精品久久久中文字幕| 欧美日韩hd| 蜜桃999成人看片在线观看| 国产精品天堂蜜av在线播放| 欧美日韩国产999| 男女av在线| 日韩一区二区中文字幕| 精品国产xxx| 亚洲欧美欧美一区二区三区| 久久一区二区电影| 激情深爱一区二区| 任你操这里只有精品| 一区二区三区午夜探花| 久久一区二区精品| 日韩精品中文字幕一区二区| 国产精品v日韩精品| 激情影院在线| 中文字幕亚洲字幕| 无码国产色欲xxxx视频| 欧美日韩高清影院| 国产精品一区二区6| 国产精品久久久久久福利一牛影视| 日本性生活一级片| 久久国产精品99久久人人澡| 内射国产内射夫妻免费频道| 欧美 亚欧 日韩视频在线 | www.亚洲.com| 亚洲成成品网站| 国产三级精品在线观看| 91久久精品网| 欧美日韩精品区| 一区二区三区四区高清精品免费观看 | 国产精品免费大片| 国产精品手机在线| 国产精久久久| 国产日韩欧美自拍| 精品国产免费人成网站| 亚洲天堂国产精品| 久久久久久久电影| zjzjzjzjzj亚洲女人| 狠狠色综合日日| 国产精品人人爽人人爽| 在线一区欧美| 欧美性潮喷xxxxx免费视频看| 欧美电影一二区| 日韩欧美亚洲在线| 国产99久久久国产精品成人免费 | 九色91av视频| 免费在线你懂的| 自拍偷拍亚洲一区| 成人高清免费观看mv| 亚洲性视频网址| 黄色网址在线播放| 亚洲天堂第二页| 福利在线午夜| 在线观看日韩www视频免费| 人成在线免费视频| 精品视频在线播放免| 视频一区二区三区国产| 日韩高清中文字幕| 亚洲色偷精品一区二区三区| 亚洲第一视频网站| 午夜性色福利影院| 日韩国产在线看| 蜜桃视频在线观看视频| 亚洲性线免费观看视频成熟| 国产高清视频在线| 中文字幕在线日韩| 黄色在线播放网站| 欧美成在线观看| 国产丝袜精品丝袜| 91国在线精品国内播放| 色是在线视频| 国产精品777| 国产成人77亚洲精品www| 91精品久久久久久综合乱菊 | 日本在线观看一区二区三区| 国产欧美日韩精品一区二区免费| 日本视频精品一区| 日本不卡高清| 蜜臀av.com| 亚洲三级观看| 中文字幕在线导航| 国产乱国产乱300精品| 逼特逼视频在线观看| 91麻豆.com| 国产又粗又猛又爽又黄的视频四季| 国产精品女人毛片| 国产精品18p| 日韩欧美在线一区| 国产精品自偷自拍| 亚洲国产成人精品久久| 国产人成在线视频| 欧美精品在线观看| 深夜在线视频| 91精品国产自产在线观看永久| 亚洲一二三区视频| 欧美一区二区福利| 久久久久久久久国产一区| av女优在线播放| 青娱乐精品视频在线| 人妻少妇偷人精品久久久任期| 99久久国产综合色|国产精品| 欧美三级视频网站| 一区二区三区国产精品| 中文字幕黄色片| 欧美一区二区视频观看视频| 蜜桃视频在线观看网站| 欧美另类极品videosbest最新版本| 在线观看爽视频| 99久re热视频这里只有精品6| 亚洲婷婷伊人| www国产免费| 日本免费在线视频不卡一不卡二 | 一炮成瘾1v1高h| 亚洲精品国精品久久99热一| 国内精品久久久久国产| 国产成人精品久久二区二区| 99re8这里有精品热视频免费| 午夜午夜精品一区二区三区文| 亚洲视频免费| 亚洲黄色av片| 久久婷婷国产综合精品青草| 青青草手机在线观看| 欧美午夜精品久久久久久超碰| 亚洲av永久无码国产精品久久| 中文字幕精品网| 亚洲性受xxx喷奶水| 成人在线观看av| 久久精品亚洲欧美日韩精品中文字幕| 国产a级一级片| 成人黄色大片在线观看| 久久av红桃一区二区禁漫| 欧美性色19p| 天天干天天操av| 欧美激情欧美激情在线五月| 亚洲老司机网| 亚洲一区二区三区精品视频| 久久精品盗摄| 日韩av一二区| 偷拍一区二区三区四区| 国产a级免费视频| 久久综合免费视频影院| 巨大黑人极品videos精品| 欧美日韩最好看的视频| 国产精品日本欧美一区二区三区| 丝袜熟女一区二区三区| 亚洲综合一区二区三区| 朝桐光av在线一区二区三区| 米奇精品一区二区三区在线观看| 欧美一区=区三区| 亚洲最新免费视频| 久久国产精品一区二区| 国产探花视频在线播放| 欧美亚洲动漫制服丝袜| 成人在线免费视频| 国产免费成人av| 亚洲破处大片| 欧美熟妇另类久久久久久多毛| 亚洲欧洲日本在线| 国产精品永久久久久久久久久| 久热精品视频在线| 亚洲国产视频二区| 亚洲熟妇无码av在线播放| 懂色av中文字幕一区二区三区| 麻豆亚洲av成人无码久久精品| 欧美成人精品二区三区99精品| 白浆在线视频| 欧美一级二级三级九九九| 日韩中文字幕亚洲一区二区va在线| 在线观看国产精品一区| 欧美亚洲一区三区| 男人天堂久久久| 97人人模人人爽人人少妇| 亚洲五月婷婷| 中文字幕日韩三级片| 欧美在线高清视频| 国内精品久久久久国产| 国产精品对白刺激久久久| 宅男噜噜噜66国产日韩在线观看| 无码人妻精品一区二区中文| 欧美伊人久久大香线蕉综合69| 欧美激情午夜| 99久久精品无码一区二区毛片| 日韩视频三区| 中文天堂资源在线| 欧美一区二区在线观看| 欧美调教sm| 在线观看欧美一区| 国产1区2区3区精品美女| 国产成人免费看| 色噜噜亚洲精品中文字幕| 欧美午夜网站| 一本大道熟女人妻中文字幕在线| 日本一区二区久久| 国产高清免费在线观看| 欧美一区二区影院| 99久久综合狠狠综合久久aⅴ| 国产精品日日摸夜夜爽| 91福利资源站| 国产天堂在线播放视频| 色涩成人影视在线播放| 国产69精品一区二区亚洲孕妇| 久久亚洲精品石原莉奈| 美女撒尿一区二区三区| 狠狠色丁香婷婷综合影院| 三级网站免费看| 欧美在线观看视频一区二区 | 国产精品久久久久久av福利| 亚洲欧美亚洲| 国产真人做爰视频免费| 日韩久久久久久| 97人人做人人爽香蕉精品| 成年人午夜免费视频| 国产精品久99| 蜜桃视频在线观看网站| 国产99午夜精品一区二区三区| 免费人成在线不卡| 久久久精品福利|