iOS App冷启动优化:二进制重排

打印 上一主题 下一主题

主题 854|帖子 854|积分 2562

原理

             二进制文件中方法的加载次序, 取决于方法在代码文件中的书写次序,而不是调用次序。 应用程序启动时会调用到的方法是有限的,但大概分散在许多个。  由于内存是分页管理的,要加载就要  整页加载  这就导致许多完全还用不到的方法,会在应用启动时就会被加载到内存,这必要开辟大量内存页,进而增加大量启动耗时。   
        如果将BeforeMain阶段用到的方法都找出来出来,让他们在同一或相近的内存页中次序提前加载,就可以大大减少应用启动时缺页异常出现的概率。

  技能要点

  
     1)罗列出应用启动时会调用到的方法,将其保存到.order文件中

  
        可行的方案是Clang插桩:

  
        

  
        起首,我们在项目的Build Settings中搜索并设置 Other C Flags/ Other C++ Flags 为 -fsanitize-coverage=func,trace-pc-guard。如果有swift代码,必要设置 Other Swift Flags 设置为 **** -sanitize-coverage=func -sanitize=undefined, 这样应用启动时全部方法都的边沿都被插入了__sanitizer_cov_trace_pc_guard(...)方法的调用。

  
        然后, 我们只必要实现__sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop)方法, 然后使用dladdr()方法, 就可以将被调用的方法信息罗列出来,然后将其写入.order文件中即可 。                

  1. //原子队列
  2. static  OSQueueHead symbolList = OS_ATOMIC_QUEUE_INIT;
  3. //定义符号结构体
  4. typedef struct {
  5.     void *pc;
  6.     void *next;
  7. }SYNode;
  8. - (void)viewDidLoad {
  9.     [super viewDidLoad];
  10.     [self genrateOrderFile];
  11. }
  12. void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
  13.   static uint64_t N;  // Counter for the guards.
  14.   if (start == stop || *start) return;  // Initialize only once.
  15.   printf("INIT: %p %p\n", start, stop);
  16.   for (uint32_t *x = start; x < stop; x++)
  17.     *x = ++N;  // Guards should start from 1.
  18. }
  19. void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
  20.     void *PC = __builtin_return_address(0);
  21.     SYNode *node = malloc(sizeof(SYNode));
  22.     *node = (SYNode){PC,NULL};
  23.     //写入队列
  24.     OSAtomicEnqueue(&symbolList, node, offsetof(SYNode, next));
  25. }
  26. // 解析队列并生成.order文件
  27. - (void) genrateOrderFile{
  28.     NSMutableArray <NSString *> * symbolNames = [NSMutableArray array];
  29.     while (YES) {
  30.         SYNode * node = OSAtomicDequeue(&symbolList, offsetof(SYNode, next));
  31.         if (node == NULL) {
  32.             break;
  33.         }
  34.         Dl_info info;
  35.         dladdr(node->pc, &info);
  36.         NSString * name = @(info.dli_sname);
  37.         BOOL  isObjc = [name hasPrefix:@"+["] || [name hasPrefix:@"-["];
  38.         NSString * symbolName = isObjc ? name: [@"_" stringByAppendingString:name];
  39.         [symbolNames addObject:symbolName];
  40.     }
  41.     //取反
  42.     NSEnumerator * enumerator = [symbolNames reverseObjectEnumerator];
  43.     //去重
  44.     NSMutableArray<NSString *> *funcs = [NSMutableArray arrayWithCapacity:symbolNames.count];
  45.     NSString * name;
  46.     while (name = [enumerator nextObject]) {
  47.         if (![funcs containsObject:name]) {
  48.             [funcs addObject:name];
  49.         }
  50.     }
  51.     [funcs removeObject:[NSString stringWithFormat:@"%s",__FUNCTION__]];
  52.    
  53.     //写入.order文件
  54.     NSString * funcStr = [funcs  componentsJoinedByString:@"\n"];
  55.     NSString * filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"demo.order"];
  56.     NSData * fileContents = [funcStr dataUsingEncoding:NSUTF8StringEncoding];
  57.     [[NSFileManager defaultManager] createFileAtPath:filePath contents:fileContents attributes:nil];
  58.     NSLog(@"%@",funcStr);
  59. }
  60. @end
复制代码
        (2)设置应用在链接时, 根据.order文件次序加载其中的符号

  
          只需在项目的Build Settings中搜索“Order File”,配置.order文件即可   

  
         


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

我爱普洱茶

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表