指针和内存
1.1 测试代码
YGPerson *p1 = [YGPerson alloc];
YGPerson *p2 = [p1 init];
YGPerson *p3 = [p1 init];
NSLog(@"%@-%p-%p",p1,p1,&p1);
NSLog(@"%@-%p-%p",p2,p2,&p2);
NSLog(@"%@-%p-%p",p3,p3,&p3);
- 通过alloc创建一个p1对象
- 再通过初始化方法创建 p2 和 p3
1.2 查看和总结
日志打印情况如下:
- p1, p2, p3 对象内存地址都是 0x600001ccc500
- 他们对应的指针地址不同 分别是 0x7ffeec8080a8,0x7ffeec8080a0,0x7ffeec808098
- 指针地址存放放在栈空间
alloc流程
1.1 探索方式
-
Control+Step into
-
Debug-Degworkflow-Always show disassembly
- 先汇编调试
- 找到对应的方法
- 然后在通过添加符号方法断点的方法调试
-
符号断点 直接添加方法符号 通过添加Symbolic Breakpoint...
- alloc
- objc_alloc
1.2 源码地址
-
opensource.apple.com 苹果源码下载地址
-
找到对应的源码下载
-
搜索对应objc 找到开源代码
-
想要了解更多调试信息
1.3 编译器优化
int lgSum(int a, int b){
return a+b;
}
int main(int argc, char * argv[]) {
int a = 10;
int b = 20;
int c = lgSum(a, b);
return 0;
}
- 第一次执行通过汇编可以 调用 lgSum方法和寄存器之间的值的传递和计算
- 通过x0或者w0寄存器可以得出 C的值
- 当再次运行 汇编语言中 找不到lgSub方法 被优化掉
1.4 alloc流程图
先大致看一下alloc流程图
1.5 allo,objc_alloc
NSObject.mm
// Calls [cls alloc].
id
objc_alloc(Class cls)
{
return callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/);
}
+ (id)alloc {
return _objc_rootAlloc(self);
}
- 最初汇编调试会执行 objc_alloc 但是源码调试点进去alloc 却是执行NSObject 的alloc类方法
- 断点到objc_alloc 会先执行这里 在执行 alloc方法
- 上面那个图可以看出先走 objc_alloc
1.6 alloc核心方法
-
_objc_rootAllocWithZone(cls, nil);
- callAlloc中的方法会执行两遍
-
_class_createInstanceFromZone
-
cls->instanceSize
- 计算需要内存空间的大小
-
calloc
- 向系统申请开辟内存,返回地址指针
-
initInstanceIsa
-
关联到相应的类
objc_alloc 和alloc都执行过calloc
1.这是llvm对alloc的优化进行标记
-
字节对齐
1.1 字节对齐算法
计算所需要的内存空间的时候会用到
uint32_t alignedInstanceStart() const {
return word_align(unalignedInstanceStart());
}
//通过算法 进行字节对齐 8字节对齐 # define WORD_MASK 7UL
static inline uint32_t word_align(uint32_t x) {
return (x + WORD_MASK) & ~WORD_MASK;
}
-
unalignedInstanceStart 获取到成员变量的内存大小
- 如果什么变量都没有 就一个isa指针 8字节
-
word_align 8字节对齐
1.2 成员变量为什么8字节对齐
为什么不用 4字节或者16字节
- cpu读取内存的时候用固定的宽度 增加读取速度
- 但会造成空间浪费
- 基本上8字节是最大的字节
- 如果用16字节会造成更多空间浪费
- 合理的用空间换取时间