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
關聯對象