1. 程式人生 > >黑馬程式設計師----oc加強筆記----記憶體管理

黑馬程式設計師----oc加強筆記----記憶體管理

                              引用計數器:

每個OC物件都有自己的引用計數器,是一個整數表示物件被引用的次數,即現在有多少東西在使用這個物件。物件剛被建立時,預設計數器值為1,當計數器的值變為0時,則物件銷燬。

                2)對引用計數器的操作 

                                 給物件傳送訊息,進行相應的計數器操作。retain訊息:使計數器+1,該方法返回物件本身release訊息:使計數器-1(並不代表釋放物件)retainCount訊息:獲得物件當前的引用計數器值 

          3)物件的銷燬

                             當一個物件的引用計數器為

0時,那麼它將被銷燬,其佔用的記憶體被系統回收。當物件被銷燬時,系統會自動向物件傳送一條dealloc訊息,一般會重寫dealloc方法,在這裡釋放相關的資源,dealloc就像是物件的“臨終遺言”。一旦重寫了dealloc方法就必須呼叫[super dealloc],並且放在程式碼塊的最後呼叫(不能直接呼叫dealloc方法)。一旦物件被回收了,那麼他所佔據的儲存空間就不再可用,堅持使用會導致程式崩潰(野指標錯誤)。

 注意;

          1) 如果物件的計數器不為0,那麼在整個程式執行過程,它佔用的記憶體就不可能被回收(除非整個程式已經退出)

分割槽 第一天(@傳智如意大師) 的第

10

非整個程式已經退出 )
         2)
任何一個物件,剛生下來的時候,引用計數器都為1。(物件一旦建立好,預設引用計數器就是3)當使用allocnew或者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;
}