手動內存管理MRC
首先介紹一下引用計數器:用來保存當前對象有幾個東西在使用它(數字)
引用計數器的作用:用來判斷對象是否應該回收內存空間(如果對象不等于nil,當引用計數器為0,此時要回收對象的內存空間)
引用計數器的操作:
retain 使得引用計數器+1
release 使的引用計數器-1
retainCount 得到引用計數器的值
如果一個對象被釋放的時候,會調用該對象的dealloc方法
注意:
內存管理的范圍:
所有的集成了NSObject的對象的內存管理
基本數據類型(int double float char struct enum )的數據內存不需要我們進行管理
內存管理的原則:
如果對象有人使用,就不應該回收
如果你想使用這個對象,應該讓這個對象 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;}
自動釋放池 :特殊的棧結構
特點:
自動釋放池的使用:
@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;}
我們可以給Person添加一個類方法,讓其創建完對象就加入到自動釋放池中
+(instancetype)person{ //Person person ---> Person //Stduent person ----> Student //創建對象 return [[[self alloc] init] autorelease]; // 返回的時對象的空間 // 能夠幫我們把對象給加入到自動釋放池}
新聞熱點
疑難解答