你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> IOS內存管理機制

IOS內存管理機制

編輯:IOS開發綜合

半自動管理內存,MRC

內存管理:如何正確釋放堆上的空間

內存壓根兒就沒釋放---------內存洩露

在使用之前,內存被釋放了------提前釋放

釋放過後又釋放內存---------重復釋放

 

非自動管理內存的使用原則:

alloc retain new以copy開頭的方法以mutableCopy開頭的方法,都要相應的使用release autorelease

自己收拾的自己工作

 

//retainCount專門用來計數引用計數

//retain,copy,new,mutableCopy給計數器加1 (方法)

//release給計數器減1(方法) 當retainCount=0,內存釋放

 

 

int main()
{
    Car *car = [[Car alloc] init];
    
    Person *p1 = [[Person alloc] init];
    [p1 setCar:[car retain]];
    NSLog(@"%ld",[[p1 car] retainCount]);
    
    Person *p2 = [[Person alloc] init];
    [p2 setCar:[car retain]];
    NSLog(@"%ld",[[p2 car] retainCount]);
    
    [[p2 car] release];
    
    NSLog(@"car = %ld",[car retainCount]);
    [p2 release];
    

    [[p1 car] release];
    NSLog(@"car = %ld",[car retainCount]);
    
    [p1 release];
    
    [car release];
}

init property setter delloc的內存管理

 

init property

 

setter dealloc

 

 


property屬性訪問聲明

 

readwritereadonlyassignretaincopynonatomic屬性的作用

 

@property是一個屬性訪問聲明,擴號內支持以下幾個屬性:

1,getter=getterName,setter=setterName,設置setter與getter的方法名

2,readwrite,readonly,設置可供訪問級別

2,assign,setter方法直接賦值,不進行任何retain操作,為了解決原類型與環循引用問題

3,retain,setter方法對參數進行release舊值再retain新值,所有實現都是這個順序(CC上有相關資料)

4,copy,setter方法進行Copy操作,與retain處理流程一樣,先舊值release,再Copy出新的對象,retainCount為1。這是為了減少對上下文的依賴而引入的機制。

copy是在你不希望a和b共享一塊內存時會使用到。a和b各自有自己的內存。

5,nonatomic,非原子性訪問,不加同步,多線程並發訪問會提高性能。注意,如果不加此屬性,則默認是兩個訪問方法都為原子型事務訪問。鎖被加到所屬對象實例級(我是這麼理解的...)。

atomic和nonatomic用來決定編譯器生成的getter和setter是否為原子操作。在多線程環境下,原子操作是必要的,否則有可能引起錯 誤的結果。加了atomic,setter函數會變成下面這樣:

  property 與@synthesize

 

當你定義了一系列的變量時,需要寫很多的getter和setter方法,而且它們的形式都是差不多的,,所以Xcode提供了@property和@synthesize屬性,@property用在 .h 頭文件中用作聲明,@synthesize用在.m 文件中用於實現。
如下,新建一個基於“Command Line Tool”的項目,名為“property”,再新建一個Student類,
傳統的寫法是:
Student.h
[cpp] view plaincopyprint?
//  
//  Student.h  
//  property  
//  
//  Created by Rio.King on 13-8-25.  
//  Copyright (c) 2013年 Rio.King. All rights reserved.  
//  
  
#import   
  
@interface Student : NSObject  
{  
    int age;  
    int no;  
}  
  
//age的getter和setter方法聲明  
- (int)age;  
- (void)setAge:(int)newAge;  
  
//no的getter和setter方法聲明  
- (int)no;  
- (void)setNo:(int)newNo;  
  
@end  

Student.m
[cpp] view plaincopyprint?
//  
//  Student.m  
//  property  
//  
//  Created by Rio.King on 13-8-25.  
//  Copyright (c) 2013年 Rio.King. All rights reserved.  
//  
  
#import "Student.h"  
  
@implementation Student  
  
//age的getter和setter方法的實現  
- (int)age  
{  
    return age;  
}  
-(void)setAge:(int)newAge  
{  
    age = newAge;  
}  
  
//no的getter和setter方法的實現  
- (int)no  
{  
    return no;  
}  
- (void)setNo:(int)newNo  
{  
    no = newNo;  
}  
  
@end  

main.m
[cpp] view plaincopyprint?
//  
//  main.m  
//  property  
//  
//  Created by Rio.King on 13-8-25.  
//  Copyright (c) 2013年 Rio.King. All rights reserved.  
//  
  
#import   
#import "Student.h"   
  
int main(int argc, const char * argv[])  
{  
  
    @autoreleasepool {  
          
        // insert code here...  
        Student *stu = [[Student alloc] init];  
        stu.age = 100;//這句相當於setter方法  
        NSLog(@"age is %i", stu.age);//這裡的 stu.age 相當於getter方法  
          
        [stu release];  
          
    }  
    return 0;  
}  

------------------------------------------------------------------------------------------------------------------------
用@property和@synthesize的寫法是:
 Student.h
[cpp] view plaincopyprint?
//  
//  Student.h  
//  property  
//  
//  Created by Rio.King on 13-8-25.  
//  Copyright (c) 2013年 Rio.King. All rights reserved.  
//  
  
#import   
  
@interface Student : NSObject  
{  
    int age;  
    int no;  
}  
  
//當編譯器遇到@property時,會自動展開成getter和setter的聲明  
@property int age;  
@property int no;  
  
  
@end  

Student.m
[cpp] view plaincopyprint?
//  
//  Student.m  
//  property  
//  
//  Created by Rio.King on 13-8-25.  
//  Copyright (c) 2013年 Rio.King. All rights reserved.  
//  
  
#import "Student.h"  
  
@implementation Student  
  
//@synthesize 會自動生成getter和setter的實現  
//@synthesize 默認會去訪問age,no,height同名的變量,,  
//如果找不到同名的變量,會在內部自動生成一個私有同名變量age,no,height,,  
//因此Student.h 中的這幾個變量也可以省略不寫。  
@synthesize age,no;  
  
@end  

main.m
[cpp] view plaincopyprint?
//  
//  main.m  
//  property  
//  
//  Created by Rio.King on 13-8-25.  
//  Copyright (c) 2013年 Rio.King. All rights reserved.  
//  
  
#import   
#import "Student.h"  
  
int main(int argc, const char * argv[])  
{  
      
    @autoreleasepool {  
          
        // insert code here...  
        Student *stu = [[Student alloc] init];  
        stu.age = 100;  
        NSLog(@"age is %i", stu.age);  
          
        [stu release];  
    }  
    return 0;  
}  

幾點說明:
1.在Xcode4.5及以後的版本中,可以省略@synthesize ,編譯器會自動幫你加上getter 和 setter 方法的實現,並且默認會去訪問
_age這個成員變量,如果找不到_age這個成員變量,會自動生成一個叫做 _age的私有成員變量。
2.建議變量名用"_"前綴作為開頭,但我看big Nerd 那本書裡是不用的,個人也比較習慣 big Nerd 的那種寫法,所以變量名就不加前綴了。Y^o^Y 

 

 

自動釋放池是什麼,如何工作

當您向一個對象發送一個autorelease消息時,Cocoa就會將該對象的一個引用放入到最新的自動釋放池。它仍然是個正當的對象,因此自動釋放池定義的作用域內的其它對象可以向它發送消息。當程序執行到作用域結束的位置時,自動釋放池就會被釋放,池中的所有對象也就被釋放。

1. ojc-c是通過一種"referring counting"(引用計數)的方式來管理內存的, 對象在開始分配內存(alloc)的時候引用計數為一,以後每當碰到有copy,retain的時候引用計數都會加一, 每當碰到release和autorelease的時候引用計數就會減一,如果此對象的計數變為了0, 就會被系統銷毀.

2. NSAutoreleasePool 就是用來做引用計數的管理工作的,這個東西一般不用你管的.

3. autorelease和release沒什麼區別,只是引用計數減一的時機不同而已,autorelease會在對象的使用真正結束的時候才做引用計數減一.

 

 

ARC

 

1. ojc-c是通過?一種"referringcounting"(引?用計數)的?方式來管理內存的,對象在開始分配內存(alloc)的時候引?用計數為?一,以後每當碰到有copy,retain的時候引?用計數都會加?一,每當碰到release和autorelease的時 候引?用計數就會減?一, 如果此對象的計數變為了0,就會被系統銷毀   ARC的規則非常簡單:只要還有一個變量指向對象,對象就會保持在內存中。使用ARC後,不需要再手動調用retain, release, autorelease,因為編譯器處理了一切。   ARC property關鍵字

新關鍵字strong,__strong, weak, __weak(“__”為雙下劃線,(unsafe_unretained,__unsafe_unretained為iOS4.0不支持weak而使用,等同於assign,目前可以不考慮)strong 強引用等同於非ARC的retain

@property (nonatomic, retain) 改為使用@property (nonatomic, strong)

成員變量默認也為strong屬性,可寫作__strong NSString *str; 或省略直接寫為NSString *str;

方法中的strong變量,在方法後會自動釋放,類的strong成員變量在類釋放時會自動釋放。

 

weak 弱引用
與assign類似,但不全相同。當對象釋放時會自動設置為nil而不需顯式的設置。

如:
__weak NSString *testStr;- (void)test
{

NSString *abc = [NSString stringWithFormat:@"abc"];testStr = abc;

abc = [NSString stringWithFormat:@"def"];

// testStr會自動等於nil, 即使沒有立刻變為nil,在下一個程序循環中也會變為nil,這點與assign不同,assign仍然會有指向空地址的指針,需要手動設為nil,否則再使用就造成crash

}
delegate及xib的outlet 的屬性應該設置為@property @property (nonatomic, weak)

copy和之前的copy一樣,復制一個對象並創建strong關聯

注意點只要還有一個變量指向對象,對象就會保持在內存中。處理不好就會造成對象不會釋放。

比如:

NSTimerNSTimer *timer;

timer = [NSTimer scheduledTimerWithTimeInterval:1 target:selfselector:@selector(timerAction) userInfo:nil repeats:YES];

timer的repeat會對self有引用,而self也對timer有引用,即使頁面返回了,self及timer也不會釋放。

解決方法是,在頁面返回前停止timer [timer_ invalidate],可視實際情況放在viewWillDisapper裡執行。(放在dealloc沒用,頁面沒有釋放不會執行dealloc)

延時執行

[self performSelector:@selector(delayFunc) withObject:nilafterDelay:5];

即使頁面返回,也必須等此延時方法執行後才會釋放。因此需要在頁面返回前執行

[NSObject cancelPreviousPerformRequestsWithTarget:self];

(當然這裡指的是一般情況,必須要此方法執行的話可以不用寫這句,特殊情況特殊處理:)

 

不過 ARC 只能作用於 Objective-C 對象,不能釋放 Core Foundation對象。 因此這裡你仍然需要調用 CFRelease()來釋放該對象。

 

ARC下__strong和__weak的區別
 

先用Xcode新建一個命令行工程

\

新建一個Person類

在.m文件中重寫dealloc函數

 

- (void)dealloc

{

NSLog(@"Person is dealloc");

}

 

 

先了解ARC的基本原理

 

/*

ARC的判斷准則:只要沒有強指針指向對象,就會釋放對象

指針分2種:

1>強指針:默認情況下,所有指針都是強指針__strong

2>弱指針: __weak

*/

 

 

打開main函數
第一個測試
int main(int argc, const char * argv[])
{

    @autoreleasepool
    {
        Person *p = [[Person alloc]init]; //有一個強指針指向Perosn對象
        //在這裡 把p為空
        p = nil; //這行代碼過後 清空指針對象沒有強指針指向 對象會被釋放
/*會打印*/
/*  Person is dealloc */
NSLog(@"-------");
    }
    return 0;
}
第二個測試
int main(int argc, const char * argv[])
{

    @autoreleasepool
    {
        Person *p = [[Person alloc]init]; //有一個強指針指向Perosn對象
        Person *p2 = p; //p2也指向Person對象 就有兩個強指針指向
        
        p = [[Person alloc]init];//創建一個新對象讓p來指向 但另外一個Person對象仍有強指針指向
        NSLog(@"-------");
    }
    //所以對象會在程序結束後釋放
    return 0;
}

下面看弱指針的測試
int main(int argc, const char * argv[])
{

    //接下來看若指針
//    __strong 聲明強指針
//    __weak   弱指針
    
    Person *p = [[Person alloc]init];
    __weak Person *p2 = p;//聲明一個弱指針 指向對象
    
    p = nil; //把強指針指向變為空 對象沒有強指針指向 會被釋放
    
    /*
     只要強指針指向的對象不存在 ARC會自動給指向該對象的弱指針清空 這樣就會防止野指針錯誤
     */
    p2 = nil; //若指針不能決定對象的釋放
    
    NSLog(@"----------");
    return 0;
}


 

\ \

 

關於ARC使用總結

 

一.OC的ARC就是自動引用計數 [提示]簡單點說就是讓編譯器完成堆空間的引用計數加減,自動釋放.程序員不再寫retain和release方法 [注意]OC的自動內存管理,不同與JAVA的垃圾回收.而是在預處理的時候,直接在應該保留的地方,添加retain,在應該釋放的地方,添加release,其實就是自動添加代碼.   二.ARC的局限性 1.使用ARC,可能因為代碼的不規范,導致內存提前釋放. 2.導入一些第三方庫,或者導入舊代碼,這些代碼不支持ARC.   三.解決ARC的局限性 1.將不使用ARC的代碼轉成ARC代碼 Edit—>Refactor—>Convert to ARC 2.ARC非ARC混編 //同一個工程中,部分文件使用ARC,部分文件不使用ARC Build phase —>Complie Source -fno-objc-arc   四.使用ARC的技巧 1.四個關鍵字 修飾引用 __strong(強引用) 缺省屬性,其修飾的對象指針,指向哪個對象,會對該對象retain,離開哪個對象,會對該對象release. __weak(弱引用) 其修飾的對象指針,指向任何對象都不會retain. 這樣的指針指向的對象隨時可能消失.如果對象消失了,這個指針會自動變成nil. //在IOS編程中,代理對象使用弱引用 __unsafe_unretained 其修飾的對象指針,指向任何對象都不retain. 當指向的對象消失,該指針不會變成nil,仍然指向已經釋放的對象 __auotoreleasing 只用來修飾需要被傳入地址的指針. 如:__autoreleasing NSError *error; &error;   2.屬性的()參數,原則上,不能寫retain copy了,只能寫strong,如果不想寫retain,可以寫weak [注意] 實際上ARC對這方面很寬松,寫了retain也沒關系   3.id指向對象,不能用void *p指向對象 int a; void *p = &a; id p = [[NSObject alloc] init];   4.C的結構體中,不能聲明對象指針.否則這個指針不會進行內存管理.   5.不能(顯示)手動調用父類的dealloc -(void)dealloc { self.name = nil; //自動調用父類的dealloc }  

 

ARC下的dealloc

 

眾所周知,iOS開發的時候,使用ARC的話,dealloc函數是不需要實現的,寫了反而會出錯。

但有些特殊的情況,dealloc函數還是需要的。

比如,在畫面關閉的時候,需要把ViewController的某些資源釋放,

在viewDidDissppear不一定合適,viewDidUnload一般情況下只在memory warning的時候才被調用。

不用ARC的情況下,我們自然會想到dealloc函數。

其實ARC環境下,也沒有把dealloc函數禁掉,還是可以使用的。只不過不需要調用[supper dealloc]了。

舉個例子,畫面上有UIWebView,它的delegate是該畫面的ViewController,在WebView載入完成後,需要做某些事情,比如,把indicator停掉之類的。

如果在WebView載入完成之前關閉畫面的話,畫面關閉後,ViewController也釋放了。但由於WebView正在載入頁面,而不會馬上被釋放,等到頁面載入完畢後,回調delegate(ViewController)中的方法,由於此時ViewController已經被釋放,所以會出錯。(message sent to deallocated instance)

解決辦法是在dealloc中把WebView的delegate釋放。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved