黑馬程式設計師----oc加強筆記----記憶體管理
引用計數器:
每個OC物件都有自己的引用計數器,是一個整數表示物件被引用的次數,即現在有多少東西在使用這個物件。物件剛被建立時,預設計數器值為1,當計數器的值變為0時,則物件銷燬。
2)對引用計數器的操作
給物件傳送訊息,進行相應的計數器操作。retain訊息:使計數器+1,該方法返回物件本身release訊息:使計數器-1(並不代表釋放物件)retainCount訊息:獲得物件當前的引用計數器值
3)物件的銷燬
當一個物件的引用計數器為
注意;
1) 如果物件的計數器不為0,那麼在整個程式執行過程,它佔用的記憶體就不可能被回收(除非整個程式已經退出)
分割槽 第一天(@傳智如意大師) 的第
非整個程式已經退出 )
2)任何一個物件,剛生下來的時候,引用計數器都為1。(物件一旦建立好,預設引用計數器就是3)當使用alloc、new或者copy建立一個物件時,物件的引用計數器預設就是1
3、記憶體管理分類:
1)MRC 手動記憶體管理
2)ARC 自動記憶體管理
4、手動記憶體管理入門
程式碼及理解:
Person類的建立,宣告部分:
#import <Foundation/Foundation.h> @interface Person : NSObject @end
Person類的實現部分:
#import "Person.h"
@implementation Person
//dealloc方法,是物件的臨終遺言的方法
//物件被銷燬的時候,會預設的呼叫該方法
//注意:dealloc 方法是系統根據引用計數器的值,自動呼叫的,
//不需要手動呼叫
- (void)dealloc
{
//1 先釋放子類自己的物件的空間
NSLog(@"Person已經掛了");
//2 再釋放父類的
[super dealloc];
}
@end
主程式:#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
//用Person 類例項化一個例項物件
Person *p = [Person new]; // 物件有沒有所有者? 有
// [p dealloc];
//證明有一個所有者
NSUInteger count = [p retainCount];
NSLog(@"count = %lu",count); // 1
//使用引用計數器+1
// Person *p2 = p; //
//Person *p2 = [p retain];
[p retain];
NSLog(@"p.retainCount = %lu",[p retainCount]); //2
//如果要回收物件? 應該想辦法 retatinCount = 0
[p release];
NSLog(@"p.retainCount = %lu",[p retainCount]); //1
[p release]; //此處執行後,p的空間被回收 //0
//證明p的空間被釋放了,可以在在Person類中,重寫dealloc方法
}
return 0;
}
5、記憶體管理的原則
1)原則
只要還有人在使用某個物件,那麼這個物件就不會被回收;只要你想使用這個物件,那麼就應該讓這個物件的引用計數器+1;當你不想使用這個物件時,應該讓物件的引用計數器-1;
2)誰建立,誰release
(1)如果你通過alloc,new,copy來建立了一個物件,那麼你就必須呼叫release或者autorelease方法
(2)不是你建立的就不用你去負責
3)誰retain,誰release
只要你呼叫了retain,無論這個物件時如何生成的,你都要呼叫release
4)總結
有始有終,有加就應該有減。曾經讓某個物件計數器加1,就應該讓其在最後-1.
6、單個物件記憶體管理(野指標問題)
程式碼及理解:
建立一個狗的類,宣告部分:
#import <Foundation/Foundation.h>
@interface Dog : NSObject{
@public
int _a;
}
-(void)eat;
@end
狗類的實現部分:
#import "Dog.h"
@implementation Dog
-(void)eat{
NSLog(@"狗正在吃一坨粑粑");
}
- (void)dealloc
{
NSLog(@"狗已經掛了");
[super dealloc];
}
@end
主程式碼及理解註釋:
#import <Foundation/Foundation.h>
#import "Dog.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
//建立一個物件
//物件建立完成以後,預設的所有者有一個,是自己,所以引用計數為1
Dog *byd = [Dog new]; //1
[byd eat]; //
NSLog(@"byd.retainCount = %lu",byd.retainCount);
//如果一個物件已經被釋放了,這個物件就稱之為殭屍物件
//
[byd release]; //0
// NSLog(@"byd.retainCount = %lu",byd.retainCount); //值已經沒有意義了
//這句話預設情況下不報錯,
//如果要讓他報錯,要開啟殭屍物件檢測
//byd指標也就是野指標
// [byd eat]; //野指標訪問
// [byd retain]; //byd 已經是殭屍物件了,不能復生
}
return 0;
}
7、單物件記憶體管理(記憶體洩露問題)
程式碼及理解註釋:
建立一個狗的類:
#import <Foundation/Foundation.h>
@interface Dog : NSObject
-(void)eat;
-(BOOL)compareColorWithOther:(Dog*)dog;
@end
#import "Dog.h"
@implementation Dog
-(BOOL)compareColorWithOther:(Dog*)dog{
[dog retain]; //讓傳入的物件的引用+1
return YES;
}
-(void)eat{
NSLog(@"狗在吃");
}
- (void)dealloc
{
NSLog(@"狗已經掛了");
[super dealloc];
}
@end
類存洩露情況總結:int main(int argc, const char * argv[]) {
@autoreleasepool {
//單個物件的記憶體洩露問題
//記憶體洩露情況1:
// 建立完成 使用之後,沒有release
// Dog *d = [[Dog alloc] init]; //1
// NSLog(@"%lu",d.retainCount); //使用d物件
//記憶體洩露情況2:
//沒有遵守記憶體管理的原則
// Dog *d = [[Dog alloc] init]; //1
// [d retain]; //2
//// [d release];
// [d release]; //1
//記憶體洩露的情況3:
//不當的使用了nil
// Dog *d = [[Dog alloc] init]; //1
// d = nil;
//
// [d eat]; //nil eat
// [d release]; // nil release
//記憶體洩露的情況4:
//在方法中對傳入的物件進行了retain
Dog *d = [[Dog alloc] init]; //1
NSLog(@"d.retainCount = %lu",d.retainCount);
//物件依然被洩露了
[d compareColorWithOther:d]; //2
NSLog(@"d.retainCount = %lu",d.retainCount);
[d release];
}
return 0;
}