1.创建非objc源码工程、iOS - App项目、
2.创建HSPerson类、并且声明几个属性
@interface HSPerson : NSObject
@property (nonatomic,copy)NSString *name;
@property (nonatomic,copy)NSString *hobby;
@property (nonatomic,assign)int age;
@property (nonatomic,assign)BOOL isBoy;
@end
3.获取一份编译好的objc-818源码备用、编译试错可参考
4.在ViewController中引入HSPerson类、并且alloc一个对象、
libSystem_initializer
libdispatch_init
_objc_init
void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_t this_thread, const char* pathToInitialize,
InitializerTimingList& timingInfo, UninitedUpwards& uninitUps)
{
......
// 初始化镜像
bool hasInitializers = this->doInitialization(context);
// 做标记让程序知道加载了完成镜像、下边会发通知
fState = dyld_image_state_initialized;
oldState = fState;
context.notifySingle(dyld_image_state_initialized, this, NULL);
if ( hasInitializers ) {
uint64_t t2 = mach_absolute_time();
timingInfo.addTime(this->getShortName(), t2-t1);
}
}
......
}
bool ImageLoaderMachO::doInitialization(const LinkContext& context)
{
CRSetCrashLogMessage2(this->getPath());
// mach-o 具有 -init 和静态初始值设定项
doImageInit(context);
doModInitFunctions(context);
CRSetCrashLogMessage2(NULL);
return (fHasDashInit || fHasInitializers);
}
5.libSystem_initializer断点函数的由来
// called by libSystem_initializer only
extern void _dyld_initializer(void);
__libkernel_init
__init_libsystem_sim_kernel
__libplatform_init
__init_libsystem_sim_platform
libSystem_initializer.libpthread_funcs
__init_libsystem_sim_pthread
libSystem_initializer.libc_funcs
_libc_initializer
_dyld_initializer
libdispatch_init
_libxpc_initializer
_container_init
__libdarwin_init
libSystem_initializer.malloc_funcs
__stack_logging_early_finished
6._objc_init: 根据 dyld-750 加载流程的探索、
1.编写探索案例
- (void)viewDidLoad {
[super viewDidLoad];
HSPerson *p = [HSPerson alloc];
HSPerson *p1 = [p init];
HSPerson *p2 = [p init];
NSLog(@"%@ %p",p,p);
NSLog(@"%@ %p",p1,p1);
NSLog(@"%@ %p",p2,p2);
}
2.此时此刻、我们想知道的是操作了同一个p对象、p、p1、p2三者的关系如何?
2021-06-06 17:27:56.313308+0800 HSAlloc[11278:1718697] <HSPerson: 0x600002260800> 0x600002260800
2021-06-06 17:27:56.313663+0800 HSAlloc[11278:1718697] <HSPerson: 0x600002260800> 0x600002260800
2021-06-06 17:27:56.313995+0800 HSAlloc[11278:1718697] <HSPerson: 0x600002260800> 0x600002260800
3.当对他们取地址时、他们的地址是否时一样的呢?
2021-06-06 17:47:16.451717+0800 HSAlloc[11721:1819862] <HSPerson: 0x600002714a00> 0x600002714a00 0x7ffee553a118
2021-06-06 17:47:16.452099+0800 HSAlloc[11721:1819862] <HSPerson: 0x600002714a00> 0x600002714a00 0x7ffee553a110
2021-06-06 17:47:16.452548+0800 HSAlloc[11721:1819862] <HSPerson: 0x600002714a00> 0x600002714a00 0x7ffee553a108
(lldb) ho address 0x7ffee553a108
address : 0x7ffee553a108, stack address (SP:0x7ffee553a100 FP: 0x7ffee553a140) -[ViewController viewDidLoad]
(lldb)
当我们想要看一看 alloc底层到底操作了什么时、我们点击系统函数、并不能看到实现部分。接下来我们来引入多种探索底层调用符号的方式。
我们想要探索alloc 的调用流程、需要先在创建处打上断点
1.在断点处、通过 Ctrl + Step into的方式、让其跳入内部实现的汇编部分、如下
HSAlloc`objc_alloc:
-> 0x106268326 <+0>: jmpq *0x1d14(%rip) ; (void *)0x0000000106268380
-> 0x106268380: pushq $0x3f
0x106268385: jmp 0x10626835c
0x10626838a: pushq $0x51
0x10626838f: jmp 0x10626835c
0x106268394: pushq $0x70
0x106268399: jmp 0x10626835c
None[-O0] 不优化:
在这种设置下, 编译器的目标是降低编译消耗,保证调试时输出期望的结果。
程序的语句之间是独立的:如果在程序的停在某一行的断点出,我们可以给任何变量赋新值抑或是将程序计数器指向方法中的任何一个语句,并且能得到一个和源码完全一致的运行结果。
Fast[-O1]大函数所需的编译时间和内存消耗都会稍微增加:
在这种设置下,编译器会尝试减小代码文件的大小,减少执行时间,但并不执行需要大量编译时间的优化。
在苹果的编译器中,在优化过程中,严格别名,块重排和块间的调度都会被默认禁止掉。此优化级别提供了良好的调试体验,堆栈使用率也提高,并且代码质量优于None[-O0]。
Faster[-O2]编译器执行所有不涉及时间空间交换的所有的支持的优化选项:
是更高的性能优化Fast[-O1]。在这种设置下,编译器不会进行循环展开、函数内联或寄存器重命名。
和Fast[-O1]项相比,此设置会增加编译时间,降低调试体验,并可能导致代码大小增加,但是会提高生成代码的性能。
Fastest[-O3] 在开启Fast[-O1]
项支持的所有优化项的同时,开启函数内联和寄存器重命名选项:
是更高的性能优化Faster[-O2],指示编译器优化所生成代码的性能,而忽略所生成代码的大小,有可能会导致二进制文件变大。还会降低调试体验。
Fastest, Smallest[-Os] 在不显着增加代码大小的情况下尽量提供高性能:
这个设置开启了Fast[-O1]项中的所有不增加代码大小的优化选项,并会进一步的执行可以减小代码大小的优化。
增加的代码大小小于Fastest[-O3]。与Fast[-O1]相比,它还会降低调试体验。
Fastest, Aggressive, Optimizations[-Ofast]与
Fastest, Smallest[-Os]`相比该级别还执行其他更激进的优化:
这个设置开启了Fastest[-O3]中的所有优化选项,同时也开启了可能会打破严格编译标准的积极优化,但并不会影响运行良好的代码。
该级别会降低调试体验,并可能导致代码大小增加。
Smallest, Aggressive Size Optimizations [-Oz] 不使用LTO
的情况下减小代码大小:
与-Os相似,指示编译器仅针对代码大小进行优化,而忽略性能优化,这可能会导致代码变慢。
参见内存对齐原则