iOS性能优化02 -- 启动优化

2022-01-07  本文已影响0人  YanZi_33

App的启动类型

App的启动时间

pre-main阶段
Load Dylibs动态库(镜像文件的加载)
Rebase重定位与Bind绑定
RunTime初始化,类的实现初始化,分类的合并
Initializers阶段
pre-main阶段的耗时计算
main()及main()之后的处理阶段
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[BLStopwatch sharedStopwatch] start];

    //其他逻辑......

    [[BLStopwatch sharedStopwatch] splitWithDescription:@"didFinishLaunchingWithOptions"];
    return YES;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    [[BLStopwatch sharedStopwatch] refreshMedianTime];

    //其他逻辑......
    
    [[BLStopwatch sharedStopwatch] splitWithDescription:@"HomeVC viewDidLoad"];
    [[BLStopwatch sharedStopwatch] stopAndPresentResultsThenReset];
}
image.png
基于二进制重排优化App的启动速度
物理内存与虚拟内存
image.png
分段(Segment)
分页(Paging)
image.png
页错误(Page Fault)
二进制重排
查看本工程的符号顺序和调整符号顺序
image.png image.png image.png
-[YYPerson walk]
-[YYPerson run]
-[ViewController viewDidLoad]
-[YYHomeViewController viewDidLoad]
image.png
如何获取App启动时的所有符号
image.png
//
//  ViewController.m
//  二进制重排
//
//  Created by liyanyan33 on 2022/1/7.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
}

- (void)test{
    NSLog(@"%s",__func__);
}

void testC(){
    
}

void(^YYBlock)(void) = ^(void) {
    NSLog(@"block");
};

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    testC();
}

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.

  void *PC = __builtin_return_address(0);
  char PcDescr[1024];
  //__sanitizer_symbolize_pc(PC, "%p %F %L", PcDescr, sizeof(PcDescr));
  printf("guard: %p %x PC %s\n", guard, *guard, PcDescr);
}
@end
image.png
//
//  ViewController.m
//  二进制重排
//
//  Created by liyanyan33 on 2022/1/7.
//

#import "ViewController.h"
#import <dlfcn.h>
#import <libkern/OSAtomic.h>

@interface ViewController ()

@end

@implementation ViewController
+ (void)load{
    
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
}

- (void)test{
    NSLog(@"%s",__func__);
}

void testC(){
    
}

void(^YYBlock)(void) = ^(void) {
    NSLog(@"block");
};

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)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSMutableArray<NSString *> * symbolNames = [NSMutableArray array];
    while (true) {
        //offsetof 就是针对某个结构体找到某个属性相对这个结构体的偏移量
        SymbolNode * node = OSAtomicDequeue(&symboList, offsetof(SymbolNode, 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];
        
        //去重
        if (![symbolNames containsObject:symbolName]) {
            [symbolNames addObject:symbolName];
        }
    }

    //取反
    NSArray * symbolAry = [[symbolNames reverseObjectEnumerator] allObjects];
    NSLog(@"%@",symbolAry);
    
    //将结果写入到文件
    NSString * funcString = [symbolAry componentsJoinedByString:@"\n"];
    NSString * filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"lb.order"];
    NSData * fileContents = [funcString dataUsingEncoding:NSUTF8StringEncoding];
    BOOL result = [[NSFileManager defaultManager] createFileAtPath:filePath contents:fileContents attributes:nil];
    if (result) {
        NSLog(@"%@",filePath);
    }else{
        NSLog(@"文件写入出错");
    }
    
}
//原子队列
static OSQueueHead symboList = OS_ATOMIC_QUEUE_INIT;
//定义符号结构体
typedef struct{
    void * pc;
    void * next;
}SymbolNode;

void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
    //if (!*guard) return;  // Duplicate the guard check.
    
    void *PC = __builtin_return_address(0);
    
    SymbolNode * node = malloc(sizeof(SymbolNode));
    *node = (SymbolNode){PC,NULL};
    
    //入队
    // offsetof 用在这里是为了入队添加下一个节点找到 前一个节点next指针的位置
    OSAtomicEnqueue(&symboList, node, offsetof(SymbolNode, next));
}
@end
image.png

参考文章:
iOS 优化篇 - 启动优化之Clang插桩实现二进制重排
iOS App启动优化(四):编译期插桩 && 获取方法符号
iOS 启动优化 + 监控实践

上一篇下一篇

猜你喜欢

热点阅读