美文网首页
iOS Block在内存中的位置及内存管理

iOS Block在内存中的位置及内存管理

作者: Yan青天 | 来源:发表于2017-01-12 17:38 被阅读0次

    一、关于block在内存的位置

    Block在内存中的位置分三种:
    1、NSGlobalBlock:类似函数,位于代码段(未引用外部变量):

    float (^sum)(float, float) = ^(float a, float b){
    
    
    
        return a + b;
    
    };
    

    2、NSStackBlock:位于栈内存,函数返回后block将无效(引用外部变量,但只能在该函数作用域内使用,出作用域该变量内存已被释放,出作用域触发block访问该变量会Crash):

    {
    
    NSArray *testArr = @[@"1", @"2"];
    
    
    
    void (^TestBlock)(void) = ^{
    
    
    
        NSLog(@"testArr :%@", testArr);
    
    };
    
    
    
    NSLog(@"block is %@", ^{
    
    
    
        NSLog(@"test Arr :%@", testArr);
    
    });
    }
    

    3、NSMallocBlock:位于堆内存(对NSStackBlock 使用copy修饰(strong 应该也可以))该类型拥有保存外部变量内存的能力。所以调用外部变量不会crash,下面将讲解对外部变量的存取管理。

    二、关于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();
    }
    

    通过观察上面的输出,得出结论 :
    1、普通的局部变量,BLOCK声明时会COPY它的值,并且拥有新的地址,也就是说block内部a 地址和外部a地址不同(如上)。互不影响。
    2、__block局部变量,BLOCK声明时会在堆中新建一个内存地址,并且BLOCK之后的所有b 或者 _blockString (如上)都是这个地址,所以后续的读写都是再这个地址上进行。会不想影响。即使不触发block 地址也已经不是原来的地址。
    3、全局变量 globstring (如上)BLOCK 访问都是 它本身的地址。直接读写操作。
    4、BLOCK引用外部对象时会强引用外部变量 ,如果该外部变量也强引用BLOCK就会造成return circle (比如self property block ,block 内部访问self 或者self的属性),为了解决这个使用weakSelf。

    以上均为测试并发表的自己的见解,只能模糊的用自己的语言描述。对于内存管理一直都是一知半解。网上看的BLOCK的结构看的不是很懂。只能通过实验的方式看地址的变化。希望大家有见解都写在评论里 帮助我加深理解,比如有文章说是__block 变量地址在BLOCK申明后地址是怎么发生改变的?希望大家多多关照。共同进步!

    相关文章

      网友评论

          本文标题:iOS Block在内存中的位置及内存管理

          本文链接:https://www.haomeiwen.com/subject/kifjbttx.html