深入浅出-iOS Block原理和内存中位置
- Posted by 微博@Yangsc_o
- 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0
#简介
今天回顾一下blcok,基本用法在我的这篇文章中有较为详细的描述,这次不再回顾,本次 block的原理和内存中的位置 是主角。
如何理解blcok
block:可以理解为匿名的函数,就是预先准备好的一段代码,在需要的时候调用。
#底层实现
block是一个指针结构体,在终端下通过clang -rewrite-objc 指令看看C++代码。
创建一个OS X 工程,写一个最简单的block
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
void (^myblock)() = ^() {
NSLog(@"hello block");
};
myblock();
}
return 0;
}
利用终端编译生成C++代码:
clang -rewrite-objc main.m
几个重要的结构体和函数简介:
- __block_impl:这是一个结构体,也是C面向对象的体现,可以理解为block的基类;
- __main_block_impl_0: 可以理解为block变量;
- __main_block_func_0: 可以理解为匿名函数;
- __main_block_desc_0:block的描述, Block_size;
1、__block_impl
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
2、__main_block_impl_0
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
3、__main_block_func_0
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_gc_5fkhcz0n6px48vzc744hmp6c0000gn_T_main_eef954_mi_0);
}
4、 __main_block_desc_0
staticstruct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
void (*myblock)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)myblock)->FuncPtr)((__block_impl *)myblock);
}
return 0;
}
- 注意事项:block容易造成循环引用,在block里面如果使用了self,然后形成强引用时,需要打断循环引用;在MRC下用_block,在ARC下使用__weak;
#关于block在内存中的位置
##深入理解
block快的存储位置(block入口的地址)可能存放在3个地方:代码区(全局区)、堆区、栈区(ARC情况下回自动拷贝到堆区、因此ARC下只有两个地方:代码区和堆区)。
- 代码区:不访问栈区的变量(如局部变量),且不访问堆区的变量(如用alloc创建的对象)时,此时block存放在代码区;
- 堆区:如果访问了堆区的变量(如局部变量),或堆区的变量(如用alloc创建的对象),此时block存方在堆区;–需要注意
- 实际是放在栈区,在ARC情况下自动拷贝到堆区,如果不是ARC则存放在栈区,所在函数执行完毕就回释放,想再外面调用需要用copy指向它,这样就拷贝到了堆区,strong属性不会拷贝、会造成野指针错区。(需要理解ARC是一种编译器特性,即编译器在编译时在核实的地方插入retain、release、autorelease,而不是iOS的运行时特性)。
- 此外代码存在堆区时,需要注意,因为堆区不像代码区不变化,堆区是动态的(不断的创建销毁),当没有强指针指向的时候就会被销毁,如果再去访问这段代码时,程序就会崩溃!所以此种情况在定义block属性时需要指定为strong or copy。block是一段代码,即不可变,所以使用copy也不会深拷贝。
如果看的不太明白,需要先补充点iOS内存的知识
##简单记忆:
- Block如果没有引用外部变量
保存在全局区(MRC/ARC一样)
- Block如果引用外部变量
ARC保存在堆区; MRC保存在栈区必须用copy修饰block;
深入浅出-iOS Block原理和内存中位置的更多相关文章
- iOS Block的本质(四)
iOS Block的本质(四) 上一篇文章iOS Block的本质(三)中已经介绍过block变量的捕获,本文继续探寻block的本质. 1. block内修改变量的值 int main(int ar ...
- # iOS Block的本质(三)
iOS Block的本质(三) 上一篇文章iOS Block的本质(二)中已经介绍过block变量的捕获,本文继续探寻block的本质. 1. block对对象变量的捕获,ARC 环境 block一般 ...
- iOS之Block总结以及内存管理
block定义 struct Block_descriptor { unsigned long int reserved; unsigned long int size; void (*copy)(v ...
- iOS底层原理总结 - 探寻block的本质(一)
面试题 block的原理是怎样的?本质是什么? __block的作用是什么?有什么使用注意点? block的属性修饰词为什么是copy?使用block有哪些使用注意? block在修改NSMu ...
- iOS - Block产生Memory Leaks循环引用导致的内存泄漏以及解决方案
在ARC(自动引用技术)前,Objective-c都是手动来分配释放 释放 计数内存,其过程非常复杂. ARC技术推出后,貌似世界和平了很多,但是其实ARC并不等同于Java或者C#中的垃圾回收,AR ...
- 文件系统的block 数据库中的block 以及内存中的page基础知识汇总(自己理解 可能有误)
1. 操作系统文件系统中的的block 文件系统中的block 是文件系统最小的读写单元,在HDD的磁盘时代, 一般block的大小可能与磁盘的扇区大小一致为 512bytes 也因为这个原因MBR启 ...
- IOS性能调优系列:使用Zombies动态分析内存中的僵尸对象
硬广:<IOS性能调优系列>第四篇,预计会有二十多篇,持续更新,欢迎关注. 前两篇<IOS性能调优系列:Analyze静态分析>.<IOS性能调优系列:使用Instrum ...
- Linux从头学03:如何告诉 CPU,代码段、数据段、栈段在内存中什么位置?
作 者:道哥,10+年的嵌入式开发老兵. 公众号:[IOT物联网小镇],专注于:C/C++.Linux操作系统.应用程序设计.物联网.单片机和嵌入式开发等领域. 公众号回复[书籍],获取 Linux. ...
- iOS图片加载到内存中占用内存情况
我的测试结果: 图片占用内存 图片尺寸 .png文件大小 1MB 512*512 316KB 4MB 10 ...
随机推荐
- 我的linux学习日记day3
ifconfig 查看网卡信息 uname 查看系统内核.版本信息 cat /etc/redhat-release uptime 查看系统负载信息 top命令的第一行信息 free 查看内存信息 f ...
- Docker之commit制作镜像
一.docker是什么? Docker是一个为开发人员和系统管理员提供分布式应用程序的开放平台.它是一个开源的容器引擎,基于Go语言并遵从Apche2.0协议开源. 功能:Docker可以让开发者打包 ...
- 聊聊Grpc使用中的坑以及怎么填
总所周知,随着云技术的发展,和业务的复杂度的上升,越来越多的系统开始拆分成独立的子模块微服务.模块之间免不了相互通信.但是随着业务量的增多,传输量也随之增大,偶发性timeout,无响应, 传输量过大 ...
- shell 并行运行。
我实在是太喜欢这个方法了.爽歪歪. 原帖 http://www.xaprb.com/blog/2009/05/01/an-easy-way-to-run-many-tasks-in-parallel/ ...
- C# 数据操作系列 - 11 NHibernate 配置和结构介绍
0. 前言 今天是NHibernate的第二篇内容,通过上一篇的内容,我们初步了解了NHibernate的创建和使用.这一篇,我继续探索NHibernate背后的秘密.嗯,就是这样. 1. NHibe ...
- 如何在Unity中画抛物线
using UnityEngine; using System.Collections; using System.Collections.Generic; [ExecuteInEditMode] p ...
- Django之forms.ModelForm
通常在Django项目中,我们编写的大部分都是与Django 的模型紧密映射的表单. 举个例子,你也许会有个Book 模型,并且你还想创建一个form表单用来添加和编辑书籍信息到这个模型中. 在这种情 ...
- 如何分析和提高(C/C++)程序的编译速度?
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://www.cnblogs.com/lihuidashen/p/129354 ...
- 在Cent OS云服务器上部署基于TP5后端代码踩坑记录_艾孜尔江撰
推荐使用镜像安装Cent OS系统,或者在纯净安装完成之后在完成Apache+MySQL+PHP的时候不要每个单独安装,因为这样会出一些三者之间版本不配的问题,网上各种说法都有,查起来也非常困难,版本 ...
- 剑指Offer之调整数组顺序使奇数位于偶数前面
题目描述 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. 思路:将奇数放进 ...