这篇文章简单讲一下启动优化的二进制重排
应用程序在运行时,使用的是虚拟内存与物理内存相结合的方法加载数据的;虚拟内存是分页管理的,当使用到某一页虚拟内存的数据时,需要将对应的真实数据加载到物理内存中,将虚拟内存与物理内存之间形成一个映射关系,这个操作称为缺页异常(page fault),并且这个操作是需耗时的。原理网上很多大神都有讲解,我就不多做解释,直接手把手教大家怎么做。
第一步:通过Clang插桩获取app启动时调用了哪些方法,生成hank.order文件
1、在项目工程的如下位置添加-fsanitize-coverage=func,trace-pc-guard
的编绎设置的标记:
2、创建一个工具类ClangHookFuncTool
ClangHookFuncTool.h代码
@interface ClangHookFuncTool : NSObject
+(NSString *)getClangHookFuncsListFilePath;
@end
ClangHookFuncTool.m代码
#import "ClangHookFuncTool.h"
#import <dlfcn.h>
#import <libkern/OSAtomic.h>
@implementation ClangHookFuncTool
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.
}
//原子队列
static OSQueueHead symbolList = OS_ATOMIC_QUEUE_INIT;
//定义符号结构体
typedef struct {
void *pc;
void *next;
}SYNode;
void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
// if (!*guard) return; // Duplicate the guard check.
/* 精确定位 哪里开始 到哪里结束! 在这里面做判断写条件!*/
void *PC = __builtin_return_address(0);
SYNode *node = malloc(sizeof(SYNode));
*node = (SYNode){PC,NULL};
//进入
OSAtomicEnqueue(&symbolList, node, offsetof(SYNode, next));
}
+(NSString *)getClangHookFuncsListFilePath{
NSMutableArray <NSString *> * 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<NSString *> *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);
return filePath;
}
@end
3、在你app的进入后首页面控制器的viewDidLoad里面调用getClangHookFuncsListFilePath方法
[ClangHookFuncTool getClangHookFuncsListFilePath];
4、链接真机,clean项目,建议删掉真机上的app,然后运行 ,可以断点看上面的方法是否调用
5、获取hank.order文件
打开xcode工程->Window->Devices And Simulators ->选中对应的工程 ->点击工程列表下的“齿轮”图标->Download Continaer,选择一个下载地址,右键下载下来的文件后显示包内容,到tmp文件夹中找到对应的hank.order文件.
第二步:将hank.order文件引入
1、将获取的hank.order文件放在项目根目录下
2、引用文件
第三步:搞定收工
去看看pre-main time时间,我这边亲测是减少了15%左右,每个app肯定不一样,快点去优化你的app吧!如果不知道怎么看pre-main time时间的,请移步我的另一篇文章iOS App启动优化(一)