Objective-C內(nèi)存管理

內(nèi)存管理

代碼1
棧-堆-數(shù)據(jù)段-只讀數(shù)據(jù)段-代碼段
地址由高到低

#include<stdio.h>
#include<stdlib.h>

void foo {
}

int a = 10;
// malloc realloc calloc 分配內(nèi)存
int main(void){
    char str1[20] = "Gello, world!";
    char *str2 = "Hello, world!";
    // str2[0] = 'G'; 修改不了
    char *str3 = (char *)malloc(1000);
    printf("棧(stack): str1 = %p\n", str1);
    printf("堆(heap): str3 = %p\n", str3);
    printf("數(shù)據(jù)段:a =  %p\n", &a);
    printf("只讀數(shù)據(jù)段 str2 = %p\n", str2);
    printf("代碼段: foo = %p\n", foo);
    return 0;
}

代碼2
任何時(shí)候希望通過函數(shù)調(diào)用修改傳入的參數(shù)
那就不能只傳入?yún)?shù)的值 而要傳參數(shù)的地址
如果傳入的參數(shù)本身是指針,那么就要使用指向指針的指針

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

// 指針的第一個(gè)用途就是實(shí)現(xiàn)跨棧操作
void get_memory(char **p, int m){
    // 指針的第二個(gè)用途就是申請(qǐng)堆空間
    *p = malloc(sizeof **p * m);
}
int main(){
    char *str = NULL;
    get_memory(&str, 100);
    // 判斷空間申請(qǐng)是否成功
    if(str){
        strcpy(str, "Hello, world!");
        printf("%s\n", str);
        // 堆空間不會(huì)隨著棧的消失而消失 需要手動(dòng)釋放
        free(str);
        str = NULL; // 經(jīng)驗(yàn),記住釋放空間后要寫上
    }
    return 0;
}

代碼3
一個(gè)函數(shù)可以返回棧空間的數(shù)據(jù),但是不能返回棧空間的地址

#include<stdio.h>

char * get_memory(){
    // 一個(gè)函數(shù)可以返回棧空間的數(shù)據(jù),但是不能返回棧空間的地址
    //char str[] = "Hello, world!";
    char *str = "Hello, world!";
    return str;
}

int main(){
    char *str = get_memory();
    if(str != NULL){
        printf("%s\n", str);
        // 不能釋放非堆空間
        // free操作跟malloc操作是成對(duì)出現(xiàn)的
        // free(str);
    }
    return 0;
}

代碼4
申請(qǐng)內(nèi)存后一定要判斷后再使用
用完內(nèi)存一定要釋放 否則有內(nèi)存泄露的風(fēng)險(xiǎn)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

char * get_memory (int m) {
    char *str =  malloc(sizeof *str * m);
    return str;
}

int main() {
    char *str = get_memory(100);
    // 申請(qǐng)內(nèi)存后一定要判斷后再使用
    if(str) {
        strcpy(str, "Hello, world!");
        printf("%s\n", str);
        // 用完內(nèi)存一定要釋放 否則有內(nèi)存泄露的風(fēng)險(xiǎn)
        free(str);
        str = NULL; // very important 
    }
}

ARC:自動(dòng)內(nèi)存管理

MRC:手動(dòng)內(nèi)存管理

不要再C的結(jié)構(gòu)體中使用對(duì)象指針,因?yàn)闊o法進(jìn)行內(nèi)存管理
堅(jiān)持使用ARC 不要使用MRC
如果非要用MRC 記?。赫l創(chuàng)建誰釋放 誰加1誰減1
自動(dòng)釋放池是可以嵌套的

ARC 模式下要正確的使用內(nèi)存最關(guān)鍵的就是書寫正確的和內(nèi)存管理相關(guān)的屬性修飾符

strong
- 對(duì)象指針一般都用 strong 表示對(duì)引用計(jì)數(shù)+1(默認(rèn)值)
weak
- 1.對(duì)象出現(xiàn)循環(huán)引用的時(shí)候必須使用 有一方必須使用 weak(破除循環(huán)引用)
- 2.一個(gè)對(duì)象的生命周期不由你自己的代碼管理
- 3.屬性是一個(gè)協(xié)議指針,也應(yīng)該使用weak
copy
- 1.確保 NSString、NSArray、NSDictionary、NSData等不可變類型的指針確確實(shí)實(shí)的指向一個(gè)不可變對(duì)象
- 2.如果屬性是一個(gè)Block類型的變量必須 copy
assign
- 1.非對(duì)象指針類型(整型、字符型、實(shí)型、布爾型、枚舉、結(jié)構(gòu)體、聯(lián)合體)都用assign
- 2.如果屬性桑對(duì)象指針 assign 相當(dāng)于 weak

EXC_BAD_ACCESS(異常的壞的訪問)
- x-code報(bào)這個(gè)錯(cuò)誤的時(shí)候,是使用了野指針,訪問了不能訪問的內(nèi)存,該內(nèi)存已經(jīng)被釋放了

要使用手動(dòng)內(nèi)存管理 設(shè)置方法


20150806081515665.png

個(gè)別文件使用手動(dòng)內(nèi)存管理 的設(shè)置方法


20150806081544108.png

內(nèi)存管理復(fù)習(xí)

//問:你說說對(duì)內(nèi)存管理的理解?(說原理:引用計(jì)數(shù))

// 手動(dòng)(MRC)原理:1.在創(chuàng)建一個(gè)對(duì)象的時(shí)候系統(tǒng)會(huì)自動(dòng)創(chuàng)建這個(gè)對(duì)象的引用計(jì)數(shù),并且賦值為1;
// 2.當(dāng)引用計(jì)數(shù)為0的時(shí)候,對(duì)象會(huì)去調(diào)用dealloc方法,來銷毀對(duì)象;
// 3.對(duì)象調(diào)用release方法會(huì)讓引用計(jì)數(shù)減1,調(diào)用retain方法讓對(duì)象的引用計(jì)數(shù)加1;

// 自動(dòng)(ARC):在ARC管理內(nèi)存的實(shí)質(zhì)還是通過引用計(jì)數(shù)器去管理的,但是程序員不再去關(guān)心引用計(jì)數(shù)器的值。在ARC環(huán)境下,系統(tǒng)會(huì)在程序編譯的時(shí)候會(huì)自動(dòng)的在合適的地方添加retain、release或者autorelease。
// 當(dāng)有強(qiáng)指針指向?qū)ο蟮臅r(shí)候,對(duì)象不銷毀;弱指針不影響對(duì)象的銷毀;指針默認(rèn)都是強(qiáng)指針

// 手動(dòng)內(nèi)存管理的原則:程序中如果出現(xiàn)alloc、retain、new必須配對(duì)出現(xiàn)一個(gè)release或者autorelease;誰創(chuàng)建誰釋放,在哪創(chuàng)建在哪釋放。

//手動(dòng)使用的
// autoReleasePool的原理和autorelease的作用
// autoReleasePool的原理:當(dāng)autoReleasePool銷毀的時(shí)候,會(huì)將自動(dòng)釋放池所有的對(duì)象調(diào)用一次release方法
// autorelease的作用:將對(duì)象放到自動(dòng)釋放池中(并不是寫在自動(dòng)釋放池大括號(hào)中的對(duì)象就是在自動(dòng)釋放池中的對(duì)象)
// 對(duì)象需要延遲銷毀的時(shí)候,可以使用autorelease,

// MRC 中符合內(nèi)存管理的setter方法的書寫(舊值release,新值retain,然后賦值)

// 屬性修飾符(strong weak copy assign retain)
// strong 控制@property實(shí)現(xiàn)符合內(nèi)存管理的setter方法,引用計(jì)數(shù)加1;修飾一般的對(duì)象
// weak 控制@property實(shí)現(xiàn)符合一般的setter方法(直接賦值的方法),修飾對(duì)象用來避免循環(huán)引用(最常用的delegate)
// copy 控制@property實(shí)現(xiàn)的setter方法,會(huì)先創(chuàng)建一個(gè)新的對(duì)象,將參數(shù)的值傳給新的對(duì)象,最后將新的對(duì)象賦值給成員變量。常用來修飾字符串、數(shù)組、字典、和block、NSData
// assign 控制@property實(shí)現(xiàn)符合一般的setter方法(直接賦值的方法) 常用來修飾基本數(shù)據(jù)類型、結(jié)構(gòu)體、枚舉、布爾型、聯(lián)合體

// retain:在MRC中相當(dāng)于strong(實(shí)現(xiàn)的setter方法 舊值release,新值retain,然后賦值) 使用的時(shí)候要避免循環(huán)引用

// 內(nèi)存管理的作用:解決內(nèi)存泄露和野指針操作
// 內(nèi)存管理需要注意什么: 解決內(nèi)存泄露和野指針操作

代碼1

#import <Foundation/Foundation.h>
#import "ZPStudent.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 1.創(chuàng)建了一個(gè)學(xué)生對(duì)象(堆上)
        // 2.創(chuàng)建了一個(gè)指針(棧上)
        // 3.指針指向了學(xué)生對(duì)象(指針中存儲(chǔ)了學(xué)生對(duì)象的地址)
        // 使用__weak這個(gè)關(guān)鍵字修飾的指針式弱指針。
        __weak ZPStudent *stu = [[ZPStudent alloc] init];
    
    }
    return 0;
}

代碼2

#import <Foundation/Foundation.h>
#import "ZPStudent.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // retainCount = 1;
        ZPStudent *stu = [[[ZPStudent alloc] init] autorelease];
        // autorelease 將對(duì)象添加到自動(dòng)釋放池中
        // autorelease 這個(gè)必須在自動(dòng)釋放池的作用域調(diào)用
        
    }//括號(hào)結(jié)束的時(shí)候,在這兒自動(dòng)釋放池會(huì)被銷毀,會(huì)調(diào)用自動(dòng)釋放池中所有對(duì)象的release方法
    return 0;
}
QFImage_2016-03-23_16.32.20.png
QFImage_2016-03-23_11.34.48.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容