iOS底层原理_13自测(一)

第十三节课 底层原理自测(一)

一、选择题
1.在LP64下,一个指针有多少个字节 (B)
A.4
B.8
C.16
D.64
解析:
1个指针8字节

2.一个实例对象的内存结构存在哪些元素(A)
A.成员变量
B.supClass
C.cache_t
D.bit
解析:
实例对象的大小由成员变量决定,而BCD是类的结构

3.下面代码sizeof(struct3)大小等于 (C)

struct LGStruct1 {
  char b;
  int c;
  double a;
  short d;
}struct1;  -- 24

struct LGStruct2 {
  double a; 
  int b;
  char c;
  short d;
}struct2; -- 16


struct LGStruct3 {
  double a;
  int b;
  char c;
  struct LGStruct1 str1;
  short d;
  int e;
  struct LGStruct2 str2;
}struct3;

A: 48
B: 56
C: 64
D: 72
解析:
整体法
LGStruct1中有个double为8字节,所以将前面的char+int=8,8+8+2=18 对齐后=24
LGStruct2 8+4+1+2 对齐后 8+8=16
LGStruct3 8+4+1+24+2+4+16 对齐后 8+8+24+8+16=64

4.下列代码: re1 re2 re3 re4 re5 re6 re7 re8输出结果 (C)

BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];     
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];   
BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]];     
BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]];  
NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);

BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];      
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];    
BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];     
BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]];   
NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);

A: 1011 1111
B: 1100 1011
C: 1000 1111
D: 1101 1111
解析:
+isKindOfClass:元类继承链 vs 传入类
-isKindOfClass:类继承链 vs 传入类
+isMemberOfClass:类的元类 vs 传入类
-isMemberOfClass:对象父类 vs 传入类

5.(x + 7) & ~7 这个算法是几字节对齐 (B)
A: 7
B: 8
C: 14
D: 16
解析:
8字节对齐(抹零后三位)
带入实际数据计算,例如(8+7)& ~7
8+7 = 1111
~7 = 1000
& = 1000

6.判断下列数据结构大小 (A)

union kc_t {
    uintptr_t bits;
    struct {
        int a;
        char b;
    };
}

A: 8
B: 12
C: 13
D: 16
解析:
联合体共用内存 ,即互斥

7.元类的 isa 指向谁, 根元类的父类是谁(B,D)
A: 自己 , 根元类
B: 自己 , NSObject
C: 根元类 , 根元类
D: 根元类 , NSObject
解析:
直接上图


13-isa走位图.png

8.查找方法缓存的时候发现是乱序的, 为什么? 哈希冲突怎么解决的(B)
A: 哈希函数原因 , 不解决
B: 哈希函数原因 , 再哈希
C: 他存他的我也布吉岛 , 再哈希
D: 他乱由他乱,清风过山岗 , 不解决
解析:
具体实现看objc源码

9.消息的流程是 (ABCD)
A: 先从缓存快速查找
B: 慢速递归查找 methodlist (自己的和父类的,直到父类为nil)
C: 动态方法决议
D: 消息转发流程
解析:
cache快速查找 - 慢速继承链递归查找 - 动态方法决议 - 消息转发(快速转发 + 慢速转发)

10.类方法动态方法决议为什么在后面还要实现 resolveInstanceMethod (A)
A: 类方法存在元类(以对象方法形式存在), 元类的父类最终是 NSObject 所以我们可以通过resolveInstanceMethod 防止 NSObject 中实现了对象方法!
B: 因为在oc的底层最终还是对象方法存在
C: 类方法存在元类以对象方法形式存在.
D: 咸吃萝卜,淡操心! 苹果瞎写的 不用管
解析:
万物皆对象 、isa走位图

二、判断题
11、光凭我们的对象地址,无法确认对象是否存在关联对象

  • 错✅
    解析:可以通过isa判断关联对象的标识

12、int c[4] = {1,2,3,4}; int *d = c; c[2] = *(d+2)

  • 对✅

  • 解析:内存偏移

13、@interface LGPerson : NSObject{ UIButton *btn } 其中 btn 是实例变量

  • 对✅

  • 解析:
    属性 = getter + setter + 成员变量
    成员变量 = 没有下划线的变量 + {}中定义
    实例变量 = 具备实例化的变量,是一种特殊的成员变量

14、NSObject 除外 元类的父类 = 父类的元类

  • 对✅

  • 解析:还是isa走位图

15、对象的地址就是内存元素的首地址

  • 对✅

  • 解析:不用解释了吧?

16、类也是对象

  • 对✅

  • 解析:万物皆对象

三、简答题
1、怎么将上层OC代码还原成 C++代码
解析:
(1)clang -rewrite-objc xxxx.m -o xxxx.cpp
(2)xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc xxxx.m -o xxxx.cpp

2、怎么打开汇编查看流程,有什么好处 ?
解析:
1、通过 Xcode-debug-debug workflow-always show disassembly 可以查看汇编;
2、查看汇编可以从更深层了解当前函数的汇编层面的执行,为 objc 源码分析提供信 息避免方向性错误,结合 memory read 可以更清楚的看到寄存器之间是如何互相配合 处理配合的;使用汇编查看流程,可以在不确定源码出处和执行流程的情况下,跟踪内 部代码,并可以找到出处!同时,结合下符号断点的方式,能够更清晰的跟踪源码实现。

3、x/4gx 和 p/x 以及 p *0 代表什么意思 解析: x/4gx : 输出一段内存地址,以 8 字节的形式输出 4 段; p/x :输出一个数据结构的首地址; p *0 : $0 为指向某一个数据空间的指针,而该指令输出的是该数据的数据结构。

4、类方法存在哪里? 为什么要这么设计?
解析:
对象方法存储在类中哦,类方法存储在元类中;
对象方法是由类实例化出来的,类是由元类实例化出来的;

这样设计的好处有以下 3 个方面:
1、底层不用对类方法和对象方法作区分,本质上都是对象方法,方法调用都可以理解 为消息发送,只不过消息的接受者即方法的查找对象不一致;
2、这样设计更加的基于对象,类的一切信息都存储在元类中,对象的一切信息都存储 在类中,类是元类的实例化对象,对象是类的实例化对象;存储也更符合面向对象的特点;
3、OC 语言设计早期借鉴了另一种 smalltalk 的语言,smalltalk 中也是这么设计的;

5、方法慢速查找过程中的二分查找流程,请用伪代码实现
解析:

  1. 二分查找的前提是数据必须有序排列;
  2. 不断的找起始位置(base)和有效数据量 (count);
  3. 当前目标位置=起始位置(base)+有效数据量(count)/2;
  4. 查找对应位置之后不断的向前偏移,主要作用为了找到第一个符合条件的数据,即找到最前面的 category 中满足条件的方法;
first = 0
probe;
base = first;
for (probe = 0;count !=0;count=count/2){
  probe = base+count/2; 
  if(key == probe){
    while(probe > first && key ==(probe - 1)){ probe--;
    }return probe;
  }
  if(key >value){
    base = probe+1;count--;
  } 
}

6、ISA_MASK = 0x00007ffffffffff8ULL 那么这个 ISA_MASK 的算法意义是什么?
解析:
这个算法主要是为了得到 isa 中存储的 class 信息,大部分 isa 都是不纯的 isa,是一个 长达 64 个 byte 位的联合体位域数据,而存储 class 信息的部分只有其中的部分 byte 位置,剩下的位置存储了其他的信息;读取的时候必须把其他无效位置的 byte 位数
据给遮盖住,所以需要使用 isa_mask,任何数据与 isa_mask 进行按位与操作,都只会 保留 isamask 对应 byte 位置的数据,这个算法的意义就是遮盖,盖住不需要的地方, 这样就能让 isa 存储更多的信息;

7、类的结构里面为什么会有 rw 和 ro 以及 rwe ?
解析:

  1. ro 属于 clean memory,在编译即确定的内存空间,只读,加载后不会改变内容的空间;
  2. rw 属于 dirty memory,rw 是运行时结构,可读可写,可以向类中添加属性、方法等, 在运行时会改变的内存;
  3. rwe 相当于类的额外信息,因为在实际使用过程中,只有很少的类会真正的改变他 们的内容,所以为避免资源的消耗就有了 rwe;
  4. 运行时,如果需要动态向类中添加方法协议等,会创建 rwe,并将 ro 的数据优先 attache 到 rwe 中,在读取时会优先返回 rwe 的数据,如果 rwe 没有被初始化,则返回 ro 的数据。

rw 中包括 ro 和 rwe,其中 rw 是 dirtymemory,ro 是 clean memory;为了让 dirty memory 占用更少的空间,把 rw 中可变的部分抽取出来为 rwe;
clean memory 越多越好,dirty memory 越少越好,因为 iOS 系统底层虚内存机制的原 因,内存不足时会把一部分内存回收掉,后面需要再次使用时从硬盘中加载出来即 swap 机制,clean memory 是可以从硬盘中重新加载的内存,iOS 中的 macho 文件动态 库都属于此类行;dirty memory 是运行时产生的数据,这部分数据不能从硬盘中重新 加载所以必须一直占据内存,当系统物理内存紧张的时候,会回收掉 clean memory 内 存,如果 dirty memory 过大则直接会被回收掉;所以 clean memory 越多越好,dirty memory 越少越好;苹果对 rw、ro、rwe 进行这么细致的划分都是为了能更好更细致 的区别 cleanmemory 和 dirty memory;
8、cache 在什么时候开始扩容 , 为什么?
解析:

  1. 一般情况下:如果当前方法 cache 之后,缓存的使用容量会超过总容量的 3/4,那么 此时就不会先插入,而是先触发扩容,扩容为原来的 2 倍,然后再插入本次的方法;
  2. 某些特殊预处理宏定义编译命令下,首次会存储满之后再开始扩容;
  3. 扩容时选用 3/4 作为负载因子是和 hash 表底层使用的链表以及红黑树的数据结 构有关,0.75 是最符合泊松分布概率计算得出的数值,在这个数值下哈希表的空间和 时间效率都是最高的;

9、objc_msgSend 为什么用汇编写 , objc_msgSend 是如何递归找到imp?
解析:
使用汇编响应速度快;
这个过程中使用了两个循环:

  • 循环 1:通过前面获取的 mask,与要查找的_cmd 进行 hash 运算,获取下标,从而得到 _cmd 对应的 bucket 地址,然后进行向前平移查找,每次平移 16 个字节,如果找到对应 的 sel,则 cacheHit;当平移到 buckets 的首地址,依然没有查找到,则进入第二个循环; 
    
  • 循环 2:首先会获取末尾 bucket 的地址,同样采用向前查找的方式,向_cmd 对应的地 址进行平移查找。
    

10、一个类的类方法没有实现为什么可以调用 NSObject 同名对象方法
解析:
这里涉及到 isa 和 superclass 的走位以及方法查找逻辑。
首先类的 isa 指向元类,在方法快速查找时,会根据类的 isa 找到元类,元类中没有该方 法,就会走到 lookUpImpOrForward 慢速查找流程中。在慢速查找流程中,会进行 for 递归查找,根据 superclass 查找到元类的父类,也就是根元类,而根元类的 superclass 指 向了 NSObject,所以会调用到 NSObject 的同名对象方法。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容