19-APP启动优化(下)

98 阅读1分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

clang 插桩

配置clang 插装参数 oc 项目去targets - build settings - other c flags 配置

-fsanitize-coverage=func,trace-pc-guard

swift 项目去targets - build settings - other swift flags 配置

-sanitize-coverage=func
-sanitize=undefined

运行项目报如下错误

undefined symbol: "___sanitizer_cov_trace_pc_guard_init", 
undefined symbol: "___sanitizer_cov_trace_pc_guard",

此时需要去llvm 官方文档实现以上两个方法,直到运行成功。

__sanitizer_cov_trace_pc_guard_init 方法里面会打印出符号化的个数__sanitizer_cov_trace_pc_guard 方法会打印出符号化的列表

**void** __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
    **static** uint64_t N;
    **if** (start == stop || *start) **return**;
    printf("INIT: %p %p\n", start, stop);
    **for** (uint32_t *x = start; x < stop; x++)
        *x = ++N;
    NSLog(@"%d",N);
}

**void** __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
//    NSLog(@"%s",__func__);
    **if** (!*guard) **return**;
    **void** *PC = __builtin_return_address(0);    
    SYNode *node = malloc(**sizeof**(SYNode));
    *node = (SYNode){PC,0};
    //插入结构体
    OSAtomicEnqueue(&symbolList, node, offsetof(SYNode, abc));
//    printf("%s\n",info.dli_sname);
}

最后一步输出符号化列表表并写入文件

//创建数组
    NSMutableArray *symbleNames = [NSMutableArray array];
    **while** (**YES**) {
        SYNode *node = OSAtomicDequeue(&symbolList, offsetof(SYNode, abc));
        **if** (node == **NULL**) {
            **break**;
        }
        Dl_info info;
        dladdr(node->pc, &info);
        //转为OC字符串方便操作
        NSString *name = @(info.dli_sname);
        //OC方法 直接添加到数组
//        if ([name hasPrefix:@"+["] || [name hasPrefix:@"-["]) {
//            [symbleNames addObject:name];
//            continue;
//        }
//        [symbleNames addObject:];
        **BOOL** isObjc = [name hasPrefix:@"+["] || [name hasPrefix:@"-["];
        NSString * symbleName = isObjc ? name : [@"_" stringByAppendingString:name];
        [symbleNames addObject:symbleName];
    }
//    symbleNames = (NSMutableArray *)[[symbleNames reverseObjectEnumerator] allObjects];
    NSEnumerator *em = [symbleNames reverseObjectEnumerator];
    //新数组存储
    NSMutableArray *funcs = [NSMutableArray arrayWithCapacity:symbleNames.count];
    NSString *name;
    **while** (name = [em nextObject]) {
        **if** (![funcs containsObject:name]) {
            [funcs addObject:name];
        }
    }
    //数组转为字符串
    NSString *funcStr = [funcs componentsJoinedByString:@"\n"];
    //文件路径
    NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"ll.order"];
    //文件内容
    NSData *file = [funcStr dataUsingEncoding:NSUTF8StringEncoding];
    //写入文件
    [[NSFileManager defaultManager] createFileAtPath:filePath contents:file attributes:**nil**];

    //获取沙盒主目录路径
    NSLog(@"%@",NSHomeDirectory());
    NSLog(@"%@",funcStr);

配置输出的order 文件:targets - buildsettings - order file

./ll.order

再次启动时,APP加载page进入内存时,启动所需要的符号都放在了前几页page,减少page加载的个数,也就减少了page fault 次数。

检测启动时间是否减少:通过工具instrument工具,system trace ,查看启动时间。

swift 项目符号化之后的方法都是混淆过的。