iOS重排启动优化

原理:

1.Page Fault

进程直接访问物理内存是不安全的,所以操作系统在物流内存上又建立了一层虚拟内存,虚拟内存进行了分页。

当进程访问一个虚拟内存Page而物流内存不存在,会触发一次缺页中断(Page Fault),分配物理内存,有需要还要从磁盘mmap读入数据

通过App Store渠道分发的App,Page Fault还会进行签名验证,所以一次Page Fault的耗时比想象的要多:

2.重排:

编译器生成二进制代码时,默认按照链接的.o顺序写文件,按照.o内部顺序写函数,如果函数跨页了,就会触发多次Page Fault,所以把函数排到一个Page里,只需要一次Page Fault

重排:

1.build Setting中搜索order file
2.添加自定义的.order地址
3.程序按照order里的内容调用方法

那如何获取程序启动时方法调用顺序

插桩:

1.Build Settings 搜索 other c flags,添加-fsanitize-coverage=trace-pc-guard参数
2.粘贴如下代码到项目
/#import "Hook.h"

/#import 

/#import 

//原子队列

static OSQueueHead symbolList = OS_ATOMIC_QUEUE_INIT;

//定义符号结构体

typedef struct {

void *pc;

void *next;

}SYNode;

void __sanitizer_cov_trace_pc_guard_init(uint32_t *start,

uint32_t *stop) {

static uint64_t N; // Counter for the guards.

if (start == stop || *start) return; // Initialize only once.

printf("INIT: %p %p\n", start, stop);

for (uint32_t *x = start; x < stop; x++)

*x = ++N; // Guards should start from 1.

}

void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {

// if (!*guard) return; // Duplicate the guard check.

// // If you set *guard to 0 this code will not be called again for this edge.

// // Now you can get the PC and do whatever you want:

// // store it somewhere or symbolize it and print right away.

// // The values of `*guard` are as you set them in

// // __sanitizer_cov_trace_pc_guard_init and so you can make them consecutive

// // and use them to dereference an array or a bit vector.

// void *PC = __builtin_return_address(0);

// Dl_info info;

// dladdr(PC, &info);

// printf("fname:%s \nfbase:%p \nsname:%s \nsaddr:%p\n",

// info.dli_fname,

// info.dli_fbase,

// info.dli_sname,

// info.dli_saddr);

//

//

// char PcDescr[1024];

// // This function is a part of the sanitizer run-time.

// // To use it, link with AddressSanitizer or other sanitizer.

//// __sanitizer_symbolize_pc(PC, "%p %F %L", PcDescr, sizeof(PcDescr));

// printf("guard: %p %x PC %s\n", guard, *guard, PcDescr);

// if (!*guard) return; // Duplicate the guard check.

/* 精确定位 哪里开始 到哪里结束! 在这里面做判断写条件!*/

void *PC = __builtin_return_address(0);

Dl_info info;

dladdr(PC, &info);

printf("fname:%s \nfbase:%p \nsname:%s \nsaddr:%p\n",

info.dli_fname,

info.dli_fbase,

info.dli_sname,

info.dli_saddr);

if (![[[NSString alloc] initWithUTF8String:info.dli_sname] containsString:@"createOrderFile"]){

// [ViewController createOrderFile];

SYNode *node = malloc(sizeof(SYNode));

*node = (SYNode){PC,NULL};

//进入,因为该函数可能在子线程中操作,所以用原子性操作,保证线程安全

OSAtomicEnqueue(&symbolList, node, offsetof(SYNode, next));

}

//

}

@implementation Hook

+(void)createOrderFile{

NSMutableArray  * symbolNames = [NSMutableArray array];

while (YES) {

SYNode * node = OSAtomicDequeue(&symbolList, offsetof(SYNode, next));

if (node == NULL) {

break;

}

Dl_info info;

dladdr(node->pc, &info);

NSString * name = @(info.dli_sname);

BOOL isObjc = [name hasPrefix:@"+["] || [name hasPrefix:@"-["];

NSString * symbolName = isObjc ? name: [@"_" stringByAppendingString:name];

[symbolNames addObject:symbolName];

}

//取反

NSEnumerator * emt = [symbolNames reverseObjectEnumerator];

//去重

NSMutableArray *funcs = [NSMutableArray arrayWithCapacity:symbolNames.count];

NSString * name;

while (name = [emt nextObject]) {

if (![funcs containsObject:name]) {

[funcs addObject:name];

}

}

//干掉自己!

[funcs removeObject:[NSString stringWithFormat:@"%s",__FUNCTION__]];

//将数组变成字符串

NSString * funcStr = [funcs componentsJoinedByString:@"\n"];

NSString * filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"hank.order"];

NSData * fileContents = [funcStr dataUsingEncoding:NSUTF8StringEncoding];

[[NSFileManager defaultManager] createFileAtPath:filePath contents:fileContents attributes:nil];

NSLog(@"##########################################funcStr");

NSLog(@"%@",funcStr);

NSLog(@"%@",filePath);

}

@end
3.- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

里面调用+(void)createOrderFile

4.把得到的hank.order文件拷贝到项目的根目录下。
5.Build Settings中搜索order file,添加hank.order文件的地址(./hank.order或者${SRCROOT}/hank.order)
6.Build Settings 中搜索 link map,如果是Yes则改回No
7.去掉 Other C Flags的参数 -fsanitize-coverage=func,trace-pc-guard
8.去掉 Other Swift Flags的参数 -sanitize-coverage=func 和 -sanitize=undefined
9.注销__sanitizer_cov_trace_pc_guard_init和__sanitizer_cov_trace_pc_guard方法

参考:https://www.jianshu.com/p/ccfa14d64b0a

https://juejin.im/post/6844904095921209351#heading-4

https://mp.weixin.qq.com/s/Drmmx5JtjG3UtTFksL6Q8Q

你可能感兴趣的:(iOS重排启动优化)