block 的内存结构衍生出来的面试题
今天在群里看到大佬们在讨论一个面试题,问如下代码在 32bit 和 64bit 系统上分别报什么错误:
#import <Foundation/Foundation.h>
int main()
{
void (^block)(void) = nil;
block();
return 0;
}
虽然有大佬一下子说出了答案,但我仍然一脸懵逼,后来经人提醒,这个考察 block 在内存中的结构,于是赶紧做了如下实验终于弄懂了为什么。
- 实验
将以上代码保存为block_test.m,在命令行编译成 C++:clang -rewrite-objc -fobjc-arc block_test.m,打开同一目录下生成的block_test.cpp文件,截取如下关键代码:
// 注释①
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
int main()
{
void (*block)(void) = __null;
// 注释 ②
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
return 0;
}
解释:
- 注释①所在的结构体是 block 在内存中的数据结构。
- 注释②是一个函数调用语句,可以简化成:
((__block_impl *)block)->FuncPtr(block),即调用__block_impl类型指针指向的结构体中FuncPtr指向的函数,由于该结构体指针指向的内容为 null,因此FuncPtr指向的位置显然不是一个函数,所以该指针指向的位置会发生一个EXC_BAD_ACCESS错误。 FuncPtr指向的位置是多少呢?根据上述__block_impl中各成员变量的排列可知FuncPtr的偏移是sizeof(void *) + sizeof(int) + sizeof(int),另外还需要考虑结构体内存对齐,参考这个链接,所以在 32bit 系统中,偏移:4 + 4 + 4 = 0x0C;64bit 系统中,偏移:8 + 8 = 0x10
结论:
- 答案:在 32bit 系统中报错:
EXC_BAD_ACCESS(address = 0x0C),在 64bit 系统中报错EXC_BAD_ACCESS(address = 0x10) - block 本质是一个结构体,在探究 block 相关的问题时,转换成
C++代码后往往就可以一目了然,比如weakSelf 为什么可以解决循环引用
- 答案:在 32bit 系统中报错:
block 的内存结构衍生出来的面试题的更多相关文章
- 从汇编代码理解 Block 的内存结构
❓ 在断点调试 iOS 程序碰到 block 作为函数的形参时,如果想知道该 block 本身的函数签名信息和函数体地址时,有哪些办法?
- block本质探寻一之内存结构
一.代码——命令行模式 //main.m #import <Foundation/Foundation.h> struct __block_impl { void *isa; int Fl ...
- Oracle之内存结构(SGA、PGA)
一.内存结构 SGA(System Global Area):由所有服务进程和后台进程共享: PGA(Program Global Area):由每个服务进程.后台进程专有:每个进程都有一个PGA. ...
- [转]oracle学习入门系列之五内存结构、数据库结构、进程
原文地址:http://www.2cto.com/database/201505/399285.html 1 Oracle数据库结构 关于这个话题,网上一搜绝对一大把,更别提书籍上出现的了,还有很多大 ...
- Java内存结构、类的初始化、及对象构造过程
概述 网上关于该题目的文章已经很多,我觉得把它们几个关联起来讲可能更好理解一下.与其它语言一样,它在执行我们写的程序前要先分配内存空间,以便于存放代码.数据:程序的执行过程其实依然是代码的执行及数据的 ...
- [转载] Oracle之内存结构(SGA、PGA)
2011-05-10 14:57:53 分类: Linux 一.内存结构 SGA(System Global Area):由所有服务进程和后台进程共享: PGA(Program Global Area ...
- JVM内存结构之堆、栈、方法区以及直接内存、堆和栈区别
JVM内存结构之堆.栈.方法区以及直接内存.堆和栈区别 一. 理解JVM中堆与栈以及方法区 堆(heap):FIFO(队列优先,先进先出):二级缓存:*JVM中只有一个堆区被所有线程所共享:对象和数 ...
- oracle内存结构
一.内存结构 SGA(System Global Area):由所有服务进程和后台进程共享: PGA(Program Global Area):由每个服务进程.后台进程专有:每个进程都有一个PGA. ...
- JAVA 对象内存结构
JAVA对象内存结构 HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header).实例数据(Instance Data)和对齐填充(Padding). 对象头 markWo ...
随机推荐
- Head First设计模式——复合模式
复合模式是HeadFirst上面详细讲的最后一个模式,其前面的模式作者认为都是成熟的经常使用的模式.所以这是详细讲解模式的最后一篇,同时这个模式讲解的篇幅也是最长的,接下来我就对其进行总结提炼进行讲解 ...
- # 爬虫连载系列(1)--爬取猫眼电影Top100
前言 学习python有一段时间了,之前一直忙于学习数据分析,耽搁了原本计划的博客更新.趁着这段空闲时间,打算开始更新一个爬虫系列.内容大致包括:使用正则表达式.xpath.BeautifulSoup ...
- 「从零单排HBase 05」核心特性region split
HBase拥有出色的扩展性,其中最依赖的就是region的自动split机制. 1.split触发时机与策略 前面我们已经知道了,数据写入过程中,需要先写memstore,然后memstore满了以后 ...
- nes 红白机模拟器 第8篇 USB 手柄支持
买了一个支持 USB OTG, 蓝牙 连接的 安卓手柄. 接到 ubunto 上 dmesg 可以看到识别出来的信息,内核已经支持了. usb - using uhci_hcd usb - usb - ...
- JSON Serialization/Deserialization in C#
因为对C#不是特别熟悉,但是最近写个c#的demo,需要对获取的的json字符串进行解析,开始使用Newtonsoft.Json.Linq尝试了以下,但是感觉操作起来比较麻烦,尤其对与JSON结构比较 ...
- 《52讲轻松搞定网络爬虫》读书笔记 —— HTTP基本原理
URI 和 URL URI :Uniform Resource Identifier,即统一资源标志符, URL :Universal Resource Locator,即统一资源定位符. 举栗子,加 ...
- Docker极简部署Kafka+Zookeeper+ElasticStack
之前写ELK部分时有朋友问有没有能一键部署的Kafka+ELK,写本文主要是填这个坑,基本上配置已经集中在一两个文件中了,理论上此配置支持ElasticStack 7.x所有版本 本文所有配置与代码均 ...
- js 模拟滚动条
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- USB概述及协议基础
USB概述及协议基础 USB的拓扑结构 USB是一种主从结构的系统.主机叫做Host,从机叫做Device(也叫做设备). 通常所说的主机具有一个或者多个USB主控制器(host controller ...
- vscode style内置auto会导致eslint格式化 对不齐报错
"files.associations": { "*.vue": "vue", // "*.js": "jav ...