內存管理
關於這篇呢,其完成在都是ARC形式,正常形態下根本不必我們去手動釋放內存,所以假如不是要面試呀、裝逼或許扎實功底的,就先別看了或許理解下即可,由於像面試時,有些面試官想看你的根底時,就有些人會問,如今任務根本不會用到。
學習目的
1. 掌握內存管理的原理
2. 掌握手動內存管理
===============================================
1.需求了解的知識
1.1內存管理
1.1.1 C的內存管理,以及費事之處
char *p = (char *)malloc(100*sizeof (char));
這是C的靜態內存分配,我們手動跟零碎請求了100個字節的內存;或許說零碎在堆裡開拓了100個字節的空間,並將這個空間的首地址前往給指針變量p。
strcpy(p,"Hello World!");
將字符串拷貝給指針變量p指向的內存空間。
puts(p);
將p指針指向的內存空間裡的字符串打印出來。
free(p);
運用完成後,手動跟零碎釋放內存空間;或許說零碎回收空間。
如上就是C裡復雜的內存管理。
C的內存管理,我們手動請求,手動釋放。這樣來看,我們只需求留意兩個問題就好了:
1,請求內存,運用完成後需求釋放,假如不釋放會形成內存洩露。
2,不能屢次釋放,假如屢次釋放,則會解體。
但是,假如項目比擬復雜,需求有幾十上百號人一同分工完成,就很容易呈現問題。
比如說我們開拓了一塊內存空間,裡寄存了一塊很有用的數據。但是,這個數據不只要我在這一塊代碼裡用,甚至有多團體,在順序的多個中央運用。這樣形成的後果就是,就算我運用完成這塊內存,我也不能去釋放他,由於我不能確定,他人在別的中央能否還需求運用這塊內存。內存洩露在所難免了。
OC的內存管理:
1.1.2 援用計數(retainCount)
關於一塊靜態請求的內存,有一團體(指針)運用,就給這個內存的計數器加1,運用完成後,就給這個計數器減1,當這個內存的援用計數為0了,我們再釋放他,這樣,下面的問題就處理了。OC,就是運用援用計數這種方式來管理內存的。
1.1.3 內存管理的黃金規律
關於援用計數來說,有一套內存管理的黃金規律:
The basic rule to apply is everything that increases the reference counter with alloc, [mutable]copy[withZone:] or retain is in charge of the corresponding [auto]release.
假如對一個對象運用了alloc、copy、mutablecopy、retain,new,那麼你必需運用
相應的release或許autorelease。
淺顯一點的說法就是誰淨化誰管理。
1.1.4 objective-C的內存管理恪守上面這個復雜的戰略:
1.你擁有你創立的對象,也就是說創立的對象(運用alloc,new,copy或許mutalbeCopy等辦法)的初始援用計數是1。
2.給對象發送retain音訊後,你擁有了這個對象 ,retainCount+1
3.當你不需求運用該對象時,發送release或許autorelease音訊保持這個對象
4.不要對你不擁有的對象發送“保持”的音訊
1.1.4 MRC和ARC
ARC Automatic Reference Counting,自動援用計數,由xcode,幫我們去管理內存。
MRC Manual Reference Counting,手動援用計數,我們手動管理內存。
Xcode 5.0 版本當前默許是ARC形式,
1.1.5 如何將工程改為MRC
xcode5,工程創立的時分是ARC的,我們假如想要MRC,需求停止如下設置。
選中工程 - target - Bulid Settings -Automatic Reference Counting改為NO。
1.1.6 ARC執行了新的規則
● 開發者不能顯示調用dealloc;不能完成和調用retain、release、retainCount和autorelease。
制止運用@selector(retain),@selector(release)等等。
開發者仍可以完成dealloc辦法,假如你想管理資源而不是變量。
ARC中自定義的dealloc辦法,不需求調用[super dealloc](其實這樣做就會招致編譯錯誤),編譯器會強迫自動鏈接到父類。
開發者仍可以對Core Foundation-style對象,運用CFRetain,CFRelease和其他相關辦法。
● 開發者不能運用NSAutoreleasePool對象。ARC下運用@autoreleasepool,它比NSAtuoreleasePool更無效率。
為了配合手動援用計數,ARC的辦法命名無限制:
● 訪問器辦法不能已new掃尾,反過去就是:開發者不能聲明一個已new掃尾的屬性,除非你給你指定一個getter
// 不正確 @property NSString *newTitle; // 正確 @property (getter=theNewTitle) NSString *newTitle;
1.1.7.野指針錯誤方式在Xcode中通常表現為:Thread 1:EXC_BAD_Access(code=EXC_I386_GPFLT)錯誤。由於你訪問了一塊曾經不屬於你的內存。
2.需求記住的知識
2.1 alloc與release
創立一個Dog類
@interface Dog : NSObject @end @implementation Dog - (void)dealloc { NSLog(@"dog dealloc"); [super dealloc]; } @end
delloc裡的析構函數,當對象銷毀的時分,會自動調用這個辦法,我們在這裡重寫這個辦法。
在main函數裡,寫入如下代碼:
int main(int argc, const char * argv[]) { @autoreleasepool { Dog *dog = [[Dog alloc] init]; } NSLog(@"順序行將加入"); return 0; }
從終端打印信息來看,順序行將加入這條打印之前,曾經打印dog dealloc,也就是說在順序運轉完畢前,dog對象曾經銷毀了。這個是ARC,由xcode幫我們管理dog對象。
將ARC改為MRC,再執行順序,dog對象並沒有銷毀,由於我們如今是手動管理了,我們需求恪守內存管理的黃金規律,Dog *dog = [[Dog alloc] init]; 我們需求對dog停止release。將main函數代碼改為如下方式:
int main(int argc, const char * argv[]) { @autoreleasepool { Dog *dog = [[Dog alloc] init]; [dog release]; } NSLog(@"順序行將加入"); return 0; }
再次執行順序,從打印可以看出,dog對象,曾經銷毀。這就是黃金規律,我們對dog停止alloc,就要對dog停止release。
留意,release 並不是銷毀對象,讓對象的援用計數減1,當對象的援用計數為0的時分,自動調用dealloc辦法,銷毀對象。
2.2 retain與retainCount
retain,將對象停止保存操作,也就是使對象的援用計數加1。
retainCount,打印一個對象的援用計數。
2.3 類的復合中運用
在下面代碼中,添加Person類
@interface Person : NSObject { // 一團體,養了一條狗(持有一條狗) Dog *_dog; } - (void)setDog:(Dog *)dog; - (Dog *)dog; @end @implementation Person /* 版本1 (有問題) 人並沒有真正持有狗,假如在main函數裡[dog release],讓dog的援用計數減1,就變為0,dog就銷毀了。 - (void)setDog:(Dog *)dog { _dog = dog; } */ /* 版本2 (有問題) 假如人再持有別的狗,就會形成第一條狗得不到釋放,內存洩露。 - (void)setDog:(Dog *)dog { _dog = [dog retain]; } */ /* 版本3 (有問題) 假如原本持有一條狗,又重新設置這條狗,先停止release,這個時分,很能夠dog就銷毀了,然後,就沒法再次retain了。 - (void)setDog:(Dog *)dog { [_dog release]; _dog = [dog retain]; } */ // 版本4 OK!,規范寫法 - (void)setDog:(Dog *)dog { if (_dog != dog) { [_dog release]; _dog = [dog retain]; } } - (Dog *)dog { return _dog; } - (void)dealloc { NSLog(@"person dealloc"); // 人在銷毀的時分,一並將持有的dog對象銷毀 [_dog release]; [super dealloc]; }
//MRC:
黃金規律:
只需運用了alloc/retain/copy/mutableCopy,new, 創立了對象
那麼就必需運用release停止釋放,
———總結一句話就是:誰創立,誰擔任釋放
retain — 使對象的援用計數+1, 假如指針需求去持有這個對象
需求運用retain
retainCount: 前往對象的援用計數值
release : — 使對象的援用計數 -1, 而不是釋放對象
dealloc:對象銷毀的時分(也就是retainCount為0的時分)自動調用這個辦法
MRC:
2.4 @property retain,assign,copy展開
2.4.1 retain展開
如上代碼裡,Person的setter和getter辦法,也可以用property,寫成如下方式
@property (nonatomic, retain) Dog *dog;
則會展開如下:
- (void)setDog:(Dog *)dog { if (_dog != dog) { [_dog release]; _dog = [dog retain]; } }
2.4.2 assign展開
//復雜數據類型 ,OC的內存管理關於復雜的數據類型 int\float…,
@property (nonatomic, assign) Dog *dog;,assign是直接賦值,則會展開如下: - (void)setDog:(QFDog *)dog { _dog = dog; }
2.4.3 copy展開 , 復制一份原來的對象
//copy 多用於字符串
@property (nonatomic, copy)NSString *name; 展開如下: - (void)setName:(NSString *)name { if (_name != name) { [_name release]; _name = [name copy]; } }
2.4 字符串內存管理
2.4.1 字符串的內存管理
// 關於字符串而言,十分不恪守黃金規律! (假如從字符串的援用計數來看,烏七八糟!) 這只是一個表象! 其實外部還是遵照的!!
// 我們要做的是,我們照舊恪守我們的黃金規律!
因而,假如是NSString,我們的property格式寫成如下: @property (nonatomic, copy) NSString *name;
2.4.2 copy和mutableCopy
2.5 數組的內存管理
結論
1)當我們創立數組的時分,數組會對每個對象停止援用計數加1
2)當數組銷毀的時分,數組會對每個對象停止援用計數減1
3)當我們給數組添加對象的時分,會對對象停止援用計數加1
4)當我們給數組刪除對象的時分,會對對象停止援用計數減1
總之,誰淨化誰管理,管好自己就可以了(數組外部也恪守內存管理)。
2.6 autorelease與autoreleasepool
在main函數裡寫如下代碼:
int main(int argc, const char * argv[]) { @autoreleasepool { Dog *dog = [[Dog alloc] init]; //dog並沒有馬上銷毀,而是延遲銷毀,將dog對象的擁有權交給了autoreleasepool [dog autorelease]; //這個是可以打印的,由於打印完dog的援用計數後,dog對象才銷毀 NSLog(@"retainCount = %lu",dog.retainCount); } NSLog(@"順序行將加入"); return 0; }
autoreleasepool相當於一個數組,假如哪個對象發送autorelease音訊,實踐將對象的擁有權交給了autoreleasepool;當autoreleasepool銷毀的時分,autoreleasepool裡持有的對象都發送一個release音訊。
2.7 加辦法的內存管理
我們用加辦法創立的對象,不必我們release,是由於類外部的完成運用了autorelease,延遲釋放
在Dog類的聲明裡添加一個加辦法
+ (id)dog;
在Dog類的完成裡停止完成
+ (id)dog
{
留意,這裡不要寫成release,假如是release,那麼剛創立就銷毀了,運用autorelease,使得將對象的擁有權交給了自動釋放池,只需自動釋放池沒有銷毀,dog對象也就不會銷毀。
return [[[Dog alloc] init] autorelease];
}
2.8 關於自動內存釋放復雜總結一下:
=====================================
ARC形式下的關鍵字:
__strong/__weak/__unsafe_unretain
開發者需求正確修飾變量。運用上面的格式來修飾變量聲明。
類名* 修飾 變量名
例如:
MyClass * __weak myWeakReference; MyClass * __unsafe_unretained myUnsafeReference;
對應的@property 參數辨別為
strong/weak/unsafe_unretain
__strong : 強援用,相當於MRC下的retain,指針對對象具有決議的占
有,默許狀況。
__weak : 弱援用,指針對對象不具有決議的占有,相當於MRC下的
assign,對象釋放後,指針賦值為nil。
__unsafe_unretain:弱援用,指針對對象不具有決議的占有,相當於MRC下的assign,對象釋放後,指針為懸垂指針(不會賦值為nil),可以會呈現野指針,不建議運用。
@property(nonatomic, strong) xxx
//set 相似於 retain 展開 [name retain]
@property(nonatomic, weak) xxx
//相似於 assign
@property(nonatomic, unsafe_unretain) xxx
//相似於 assign
【iOS開發-內存管理】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!