1.苹果objc源码下载算法
2.源码编译xcode
3.准备调试代码:缓存
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface ABPerson : NSObject
@end
NS_ASSUME_NONNULL_END
复制代码
#import "ABPerson.h"
@implementation ABPerson
@end
复制代码
#import "ViewController.h"
#import "ABPerson.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
ABPerson *p1 = [ABPerson alloc];
ABPerson *p2 = [p1 init];
ABPerson *p3 = [p1 init];
NSLog(@"%@ - %p - %p",p1,p1,&p1);
NSLog(@"%@ - %p - %p",p2,p2,&p2);
NSLog(@"%@ - %p - %p",p3,p3,&p3);
}
复制代码
1.添加一个alloc
符号断点,步骤以下: markdown
2.在调试代码alloc
那一行添加一个断点app
3.运行项目,断点会断点下面这个位置,可是这不是本身代码
alloc
调用的,,由于在调用我准备代码alloc
以前,系统也会调用alloc
,初始化不少东西。函数
4.取消下图断点以下:oop
5.点击红框图标,执行下一步post
6.再将刚才取消的断点,使其生效,以下:优化
7.点击红框图标,执行下一步 ui
8.此时咱们看到libobjc.A.dylib
库下的[NSObject alloc]
就是本身代码alloc
调用的,ABPerson
继承NSObject
9.接下来就能够经过库名称、方法名在objc源码中探索
1.删除符号断点,运行项目,在当前断点位置,按住control键点击红框图标
2.当出现调用
objc_alloc
时,下个objc_alloc
的符号断点,执行下一步
3.获得库的名称了和函数名称了
1.当断点断到本身的代码后,查看汇编 2.在汇编下断点的位置,找到了函数调用
3.下符号断点
objc_alloc
,方法如上
打开编译好的源码,搜索alloc {
进入
_objc_rootAlloc
进入
callAlloc
若是
!cls->ISA()->hasCustomAWZ()
成立,执行_objc_rootAllocWithZone
,再执行objc_msgSend
。
在ABPerson的工程中依次给alloc
、_objc_rootAlloc
、callAlloc
、 _objc_rootAllocWithZone
下符号断点
发现断点并无断到
callAlloc
,这是编译器作了优化。
#import <Foundation/Foundation.h>
int ABSum(int a,int b){
return a + b;
}
int main(int argc, const char * argv[]) {
int a = 10;
int b = 20;
int c = ABSum(a, b);
NSLog(@"----%d",c);
return 0;
}
复制代码
汇编查看:
这是未优化的,
callq
调用了ABSum
函数
xcode配置优化等级 再次运行
直接使用
$0x1e
,也就是30,并未调用ABSum
函数,被优化了。
解释了编译器优化,接下来看_objc_rootAllocWithZone
实现
跟进去看一下
_class_createInstanceFromZone
实现
1.源码工程编译target选择KCObjcBuild
2.查看main.m文件,修改代码:
int main(int argc, const char * argv[]) {
@autoreleasepool {
LGPerson *p = [LGPerson alloc] ;
NSLog(@"%@",p);
}
return 0;
}
复制代码
3.修改LGPerson代码:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface LGPerson : NSObject
@end
NS_ASSUME_NONNULL_END
复制代码
4.打上断点运行工程
5.按照上面断点调试方式,确保
_class_createInstanceFromZone
是被LGPerson
调用
6.step into instanceSize
若是有缓存就返回缓存的大小。
7.step into fastInstanceSize
拿到size 再经过
align16
,16字节对齐 16字节对齐算法,当x=16时,
(16+15)& ~15
31&~15
31 的二进制表示:0001 1111
15 的二进制表示:0000 1111
~15的二进制表示:1111 0000
31&~15: 0001 0000
十进制表示就是16
8.没有就经过alignedInstanceSize
计算
经过
unalignedInstanceSize
拿到实例对象的实际大小,再经过word_align
进行8字节对齐
8字节对齐算法: 当前LGPerson
并无成员变量,只继承了NSObjct
的isa
,因此x=8
(8+7)& ~7
15&~7
15 的二进制表示:0000 1111
7 的二进制表示:0000 0111
~7的二进制表示:1111 1000
15&~7: 0000 1000
十进制表示就是8
计算的结果还要再作一次处理,至少要16个字节
1.修改LGPerson代码:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic) int age;
@property (nonatomic) int height;
@property (nonatomic, copy) NSString *nickName;
@end
NS_ASSUME_NONNULL_END
复制代码
2.修改main.m代码:
int main(int argc, const char * argv[]) {
@autoreleasepool {
LGPerson *p = [LGPerson alloc] ;
p.name = @"Cooci";
p.nickName = @"KC";
p.age = 18;
p.height = 180;
NSLog(@"%@",p);
}
return 0;
}
复制代码
可以看到前8个字节存储isa相关信息,age和height共用8个字节就够了,因此LGPerson
的实例对象占用了32个字节大小。
instanceSize
执行完后,须要一个obj做为返回object_cxxConstructFromClass
的参数 默认obj是一个脏地址,当执行了
calloc
,会对它进行从新赋值。
接着往下看
最后都会调用
initIsa
关联对象