⼀、記憶體管理的⽅式
1、記憶體常見問題
(1)野指針異常:指針操作已經銷毀的對象
指針指向某對象,該對象釋放後,該指針即為野指針,對其操作造成野指針異常。
原因:過度釋放。
(2)記憶體溢出:超出記憶體上限
iOS給每個應⽤程式提供了⼀定的記憶體,⽤于程式的運⾏。iPhone 3GS記憶體 30M左右,iPhone 5S 記憶體80M左右。⼀旦超出記憶體上限,程式就會Crash。
2、記憶體管理的方式
(1)垃圾回收(gc) | OC支援 — OS X開發 支援 | iOS 不支援
程式員隻需要開辟記憶體空間,不需要⽤代碼顯式地釋放,系統來判斷哪些空間不再被使⽤,并回收這些記憶體空間,以便再 次配置設定。整個回收的過程不需要寫任何代碼,由系統⾃動完成垃圾回 收。Java開發中⼀直使⽤的就是垃圾回收技術。
(2)MRC (Manual Reference Count) | ⼈⼯引⽤計數 | iOS支援
手動操作引用計數,手動調用控制引用計數的方法
記憶體的開辟和釋放都由程式代碼進⾏控制。
(3)ARC (Auto Reference Count) | ⾃動引⽤計數 | iOS支援
自動操作引用計數,編譯器調用引用計數的方法
iOS 5.0的編譯器特性,它 允許⽤戶隻開辟空間,不⽤去釋放空間。它不是垃圾回收!它的本質 還是MRC,隻是編譯器幫程式員預設加了釋放的代碼。
⼆、記憶體管理機制
C語⾔中:使⽤malloc和free,進⾏堆記憶體的建立和釋放。堆記憶體隻 有正在使⽤和銷毀兩種狀态。 實際開發中,可能會遇到,兩個以上的指針使⽤同⼀塊記憶體。C語⾔ ⽆法記錄記憶體使⽤者的個數。
OC采⽤引⽤計數機制管理記憶體,當⼀個新的引⽤指向對象時,引⽤ 計數器就遞增,當去掉⼀個引⽤時,引⽤計數就遞減。當引⽤計數到 零時,該對象就将釋放占有的資源。
1、引⽤計數
(1)引用計數 标記程式運作期間,對象被引用的次數
(2)通過操作引用計數,控制對象是否被銷毀。
(3)當引用計數應該減為0時,對象自動被銷毀,存儲空間被回收
2、操作引⽤計數的⽅法
alloc\ retain\ copy\ release\ autorelease
(1)造成引用計數增加
除了NSString的對象使用copy 其餘的對象類型都聲明成retain
+alloc 目前對象 計數 0 -> 1
Person * p = [[Person alloc] init];
NSLog(@"%lu", p.retainCount);
-retain 目前對象 計數 加1
指針的引用
新對象與原對象指向相同對象
[pretain];
NSLog(@"%lu", p.retainCount);
Person * p3 = [p2 retain];
NSLog(@"%lu,%lu,%lu", p.retainCount, p2.retainCount, p3.retainCount);
-copy 原來的對象計數 不變 新的對象 0 -> 1
拷貝
詳情見四
(2)造成引用計數減少
release 目前對象 立即減1
// 調用release,實作引用計數-1
[p release];
NSLog(@"%lu", p.retainCount);
[p release];
NSLog(@"%lu", p.retainCount);
// 當引用計數應該減為0時,對象被銷毀,存儲空間被回收(系統完成)
// person對象被銷毀(隻是标記删除,并不清空資料),不建議通過指針操作
// 對象被銷毀後,列印引用計數顯示結果為1
[p release];
NSLog(@"%lu", p.retainCount); // 應該減為0
autorelease 目前對象 延遲減1 非立即
[pe1 autorelease]; // 未來的某個時刻引用計數-1(管理其的自動釋放池release時)
autoreleasepool的使⽤:
第一種寫法:将對象寫在pool的建立和release之間
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Person * p = [[Person alloc] init]; // 1
[p retain]; // 2
[p retain]; // 3
NSLog(@"%lu", pool.retainCount);
[p autorelease]; // 3
[p autorelease]; // 3
NSLog(@"%lu", pool.retainCount);
// release銷毀自動釋放池(扔掉垃圾桶)
[pool release];
// drain清空自動釋放池(隻倒垃圾)
//[pool drain];
第二種寫法:mrc支援兩種,arc隻支援第二種
Person * pe = [[Person alloc] init]; //1
[pe retain]; // 2
NSLog(@"--- %lu", pe.retainCount);
@autoreleasepool {
[pe autorelease]; // 2
NSLog(@"--- %lu", pe.retainCount);
}
NSLog(@"--- %lu", pe.retainCount); // 1
3、銷毀對象
dealloc 引用計數将要減為0時,對象自動調用
(1)繼承自NSObject,可以不實作,編譯器預設實作
(2)如果實作dealloc方法
- (void)dealloc
{
代碼
[super dealloc];
}
QA:
dealloc和release到底執行了什麼操作?
三、記憶體管理的基本原則
引⽤計數的增加和減少相等,當引⽤計數降為0之後,不應該再使⽤這塊記憶體空間。
正常情況
凡是使⽤了alloc、retain或者copy讓記憶體的引⽤計數增加了,就需 要使⽤release或者autorelease讓記憶體的引⽤計數減少。在⼀段代碼 内,增加和減少的次數要相等。
異常情況:
假設目前pe指向的對象的引用計數為1
如果不寫[pe release]; main函數運作結束後,局部變量pe被銷毀,沒有指針指向對象,造成記憶體洩漏
如果寫了不止一句[pe release];造成過度釋放。本質:野指針異常(pe 操作已釋放的對象)。
3、文法糖
利用文法糖建立的對象和類方法建立的對象相同,均由自動釋放池管理。
NSArray * arr = @[@"asfe",@"23",@"2"];
NSNumber *number = @123;
四、掌握copy的實作
自定義對象的拷貝要實作NSCopying協定和NSMutablecopying協定,但是在NSCopying協定中也能實作本質上的深拷貝是以隻需實作一個方法就可以。
1、深淺拷貝
深拷貝 拷貝的是對象,即建立了新的對象
淺拷貝 拷貝的是指針,即操作的是原來的對象,沒有建立新的對象
// 實作淺拷貝
- (id)copyWithZone:(NSZone *)zone
{
return [self retain];
}
// 深拷貝
- (id)copyWithZone:(NSZone *)zone
{
// Person * p = [[Person allocWithZone:zone] init]; // 以前的iOS版本需要這樣寫,如果需要向下相容可以寫這句代碼
Person * p = [[Person alloc] init];
p.name = self.name; // self表示調用copy方法的對象。即被拷貝的對象
return p;
}
2、copy 和 mutableCopy
對象調用copy方法得到的是不可變的對象
對象調用mutableCopy得到的是可變的對象
不可變對象建立不可變對象(NSString)為淺copy其餘全為深copy
NSZombieEnabled 環境變量
當設定NSZombieEnabled環境變量後,一個對象銷毀時會被轉化為_NSZombie,設定NSZombieEnabled後,當你向一個已經釋放的對象發送消息,這個對象就不會向之前那樣Crash或者産生一個難以了解的行為,而是放出一個錯誤消息,然後以一種可預測的可以産生debug斷點的方式消失, 是以我們就可以找到具體或者大概是哪個對象被錯誤的釋放了。
注意:NSZombieEnabled環境變量需要每次建立工程時設定,且上傳之前必須關閉
*** -[__NSArray addObject:]:message sent to deallocated instance 0x6557370
Xcode打開僵屍對象:
個人總結:NSString 建立的字元串内容為ASCII,則在常量區建立常量字元串,否則,在堆區建立(待檢驗)
NSString * str1 = @"易荟雲";請問str1的retainCount是多少?
@""在常量區,str1的retainCount為最大值。
drain與release差別
在MRC下,兩者基本一樣,在GC環境下,release 是一個no-op(無效操 作),是以無論是不是gc都使用drain
iOS有沒有垃圾回收?autorelease 和垃圾回收制(gc)有什麼關系?
沒有。autorelease隻是延遲釋放,gc是每隔一段時間詢問程式,看是否有無指針指向的對象,若有,就将它回收。他們兩者沒有什麼關系。
版權聲明:本文為CSDN部落客「weixin_34072637」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。
原文連結:https://blog.csdn.net/weixin_34072637/article/details/91729598