iOS Block在內(nèi)存中的位置及內(nèi)存管理

一、關(guān)于block在內(nèi)存的位置

Block在內(nèi)存中的位置分三種:
1、NSGlobalBlock:類似函數(shù),位于代碼段(未引用外部變量):

float (^sum)(float, float) = ^(float a, float b){



    return a + b;

};

2、NSStackBlock:位于棧內(nèi)存,函數(shù)返回后block將無效(引用外部變量,但只能在該函數(shù)作用域內(nèi)使用,出作用域該變量內(nèi)存已被釋放,出作用域觸發(fā)block訪問該變量會Crash):

{

NSArray *testArr = @[@"1", @"2"];



void (^TestBlock)(void) = ^{



    NSLog(@"testArr :%@", testArr);

};



NSLog(@"block is %@", ^{



    NSLog(@"test Arr :%@", testArr);

});
}

3、NSMallocBlock:位于堆內(nèi)存(對NSStackBlock 使用copy修飾(strong 應該也可以))該類型擁有保存外部變量內(nèi)存的能力。所以調(diào)用外部變量不會crash,下面將講解對外部變量的存取管理。

二、關(guān)于block外部變量的存取管理

#######在這里只討論ARC機制下

- (void)test

{
int a = 0;
__block int  b = 0;
self.globstring = @"1";
NSString *__localString = @"1";
__block NSString *_blockString = @"1";
printf("a address: %p\n", &a); //a address: 0x7fff56516b3c

printf("b address: %p\n", &b); //b address: 0x7fff56516b30

printf("local address: %p\n", &__localString); //local address: 0x7fff56516b00
printf("_block address: %p\n", &_blockString); //_block address: 0x7fff56516af8
printf("glob address: %p\n", &_globstring); //glob address: 0x7fed5bc09520

void (^TestBlock)(void) = ^{
    printf("a value: %d\n", a); //a value: 0
    printf("b value: %d\n", b); //b value: 1
    printf("b address: %p\n", &b); //b address: 0x60800002a7f8
    
    printf("local address: %p\n", &__localString); //       local address: 0x6080000979a0
    NSLog(@"lockstring is : %@\n", __localString); //lockstring is : 1
    
    printf("_blcok address: %p\n", &_blockString); //_blcok address: 0x6080000470d8
    NSLog(@"_blcokstring is : %@\n", _blockString); //_blcokstring is : 2

    printf("globaddress: %p\n", &_globstring); //globaddress: 0x7fed5bc09520
    NSLog(@"globstring is : %@\n", _globstring); //globstring is : 2
    
};
 __weak typeof(self) this = self;
self.copyBlock = ^{
    printf("a value: %d\n", a); //a value: 0
    printf("b value: %d\n", b); // b value: 1
    printf("b address: %p\n", &b); // b address: 0x60800002a7f8
    printf("copy block local address: %p\n", &__localString); //copy block local address: 0x608000099660
    
    NSLog(@"copy block string is : %@\n", __localString); //copy block string is : 1
    
    printf("_blcok address: %p\n", &_blockString); //_blcok address: 0x6080000470d8
    
    NSLog(@"_blcokstring is : %@\n", _blockString); //_blcokstring is : 2
    
    printf("glob address: %p\n", &_globstring); //glob address: 0x7fed5bc09520
    
    NSLog(@"string is : %@\n", this.globstring); //string is : 2

};
a = 1;
b = 1;
printf("a address: %p\n", &a); //local address: 0x7fff56516b3c
printf("b address: %p\n", &b); //_block address: 0x60800002a7f8

printf("local address: %p\n", &__localString); //local address:  0x7fff56516b00
printf("_block address: %p\n", &_blockString); //_block address: 0x60800002a7f8

__localString = nil;
_blockString = @"2";
self.globstring = @"2";

TestBlock();
self.copyBlock();
}

通過觀察上面的輸出,得出結(jié)論 :
1、普通的局部變量,BLOCK聲明時會COPY它的值,并且擁有新的地址,也就是說block內(nèi)部a 地址和外部a地址不同(如上)?;ゲ挥绊?。
2、__block局部變量,BLOCK聲明時會在堆中新建一個內(nèi)存地址,并且BLOCK之后的所有b 或者 _blockString (如上)都是這個地址,所以后續(xù)的讀寫都是再這個地址上進行。會不想影響。即使不觸發(fā)block 地址也已經(jīng)不是原來的地址。
3、全局變量 globstring (如上)BLOCK 訪問都是 它本身的地址。直接讀寫操作。
4、BLOCK引用外部對象時會強引用外部變量 ,如果該外部變量也強引用BLOCK就會造成return circle (比如self property block ,block 內(nèi)部訪問self 或者self的屬性),為了解決這個使用weakSelf。

以上均為測試并發(fā)表的自己的見解,只能模糊的用自己的語言描述。對于內(nèi)存管理一直都是一知半解。網(wǎng)上看的BLOCK的結(jié)構(gòu)看的不是很懂。只能通過實驗的方式看地址的變化。希望大家有見解都寫在評論里 幫助我加深理解,比如有文章說是__block 變量地址在BLOCK申明后地址是怎么發(fā)生改變的?希望大家多多關(guān)照。共同進步!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容