標籤:
手動記憶體管理MRC
首先介紹一下引用計數器:用來儲存當前對象有幾個東西在使用它(數字)
引用計數器的作用:用來判斷對象是否應該回收記憶體空間(如果對象不等於nil,當引用計數器為0,此時要回收對象的記憶體空間)
引用計數器的操作:
retain 使得引用計數器+1
release 使的引用計數器-1
retainCount 得到引用計數器的值
如果一個對象被釋放的時候,會調用該對象的dealloc方法
注意:
- dealloc方法是NSObject 的,一般我們要重寫dealloc方法
- 在dealloc 方法的內部,要調用 [super dealloc];
記憶體管理的範圍:
記憶體管理的原則:
如果對象有人使用,就不應該回收
如果你想使用這個對象,應該讓這個對象 retain一次
如果你不想使用這個對象了,應該讓這個對象 relase一次
誰建立 誰release
誰 retain 誰 release
記憶體管理研究的內容:
- 野指標:
1)定義的指標變數沒有初始化 2)指向的空間已經被釋放
記憶體泄露:
{ Person *p = [Person new]; }/* p 棧區 [Person new]; 堆區 如果棧區的p已經釋放了,而堆區的空間還沒有釋放,堆區的空間就被泄露了*/
set方法記憶體管理
// Dog* _dog; // 對於對象作為另外一個類的執行個體變數 - (void)setDog:(Dog*)dog { // 判斷對象是否是原對象 if(_dog != dog) { //2) release舊值 [_dog release]; // retain 新的值,並且賦值給執行個體變數 _dog = [dog retain]; } }
迴圈retain問題
迴圈的retain 會導致兩個對象都會記憶體泄露
防止方法:
讓某個對象多釋放一次 (注意順序)
一端使用 assign 一端使用retain(推薦使用)
NSString類的記憶體管理問題
#import <Foundation/Foundation.h>int main(int argc, const char * argv[]) { @autoreleasepool { //定義字串 //字串的常量池, //如果你需要的字串在常量池中已經存在了,不會分配記憶體空間 //使用字串的時候, // @"abc" stringWithString alloc initWithString 都在常量區/ //0x100001030 小 NSString *str1 = @"abc"; //@"abc" 字串的常量 NSString *str3 = [NSString stringWithString:@"abc"]; //常量區 NSString *str5 = [[NSString alloc] initWithString:@"abc"]; //也在常量區 NSString *str6 = [[NSString alloc] init];//常量區 str6 = @"abc"; //0x100202030 大 //如果在常量區 str2 str4 地址應該是一樣的 //實際上不一樣的,所以 str2 str4都在堆區 NSString *str2 = [NSString stringWithFormat:@"abc"]; //不是在棧區,在堆區 NSString *str4 = [[NSString alloc] initWithFormat:@"abc"];//不是在棧區,在堆區 //0x7fff5fbff764 int a = 10; //棧區 NSLog(@"str1 = %@,%p,%lu",str1,str1,str1.retainCount); NSLog(@"str2 = %@,%p,%lu",str2,str2,str2.retainCount); NSLog(@"str3 = %@,%p,%lu",str3,str3,str3.retainCount); NSLog(@"str4 = %@,%p,%lu",str4,str4,str4.retainCount); NSLog(@"str5 = %@,%p,%lu",str5,str5,str5.retainCount); NSLog(@"str6 = %@,%p,%lu",str6,str6,str6.retainCount); NSLog(@"a = %p",&a); } return 0;}
自動釋放池 :特殊的棧結構
特點:
- 對象可以加入到自動釋放池中
- 自動釋放池結束的時候,會給池中的對象發送一條 release訊息
自動釋放池的使用:
- 建立自動釋放池
@autoreleasepool { }
2. 加入自動釋放池
/* 在自動釋放池中 [對象 autorelease];*/
類比一個Person類 類中有個一個對象方法- (void)run;
#import <Foundation/Foundation.h>#import "Person.h"int main(int argc, const char * argv[]) { //1 建立自動釋放池 Person *p = [Person new]; // p 1 @autoreleasepool {//自動釋放池開始 [p run]; NSLog(@"%lu",p.retainCount); // 1 // [p autorelease] 把對象p加入到自動釋放池中 // 注意:加入到自動釋放池中以後, 引用計數不會變化 [p autorelease]; //加入自動釋放池, NSLog(@"%lu",p.retainCount); // 1 [p run]; }//自動釋放池結束 [p release]; [p run]; return 0;}
Objective-C知識總結(3)