一永票、啟動(dòng)優(yōu)化
冷啟動(dòng):第一次啟動(dòng)App
熱啟動(dòng)
啟動(dòng)優(yōu)化一般講的是冷啟動(dòng)
啟動(dòng)階段:main函數(shù)之前、main函數(shù)之后
main 階段:
1、懶加載
2钝的、發(fā)揮CPU的價(jià)值(多線程進(jìn)行初始化)
3惧辈、啟動(dòng)時(shí)避免使用Xib琳状、stroyboard
階段一、main函數(shù)之前
打印啟動(dòng)時(shí)間
- 添加
DYLD_PRINT_STATISTICS
- dylib loading time: 加載動(dòng)態(tài)庫(kù) (優(yōu)化:建議不要大于6個(gè))
- rebase/binding time: 修正內(nèi)部偏移指針/外部符號(hào)綁定 (優(yōu)化:減少OC類) 優(yōu)化少
- ObjC setup time: OC類的注冊(cè) (優(yōu)化:減少OC類) 優(yōu)化少
- initializer time: 加載load方法 (優(yōu)化:使用懶加載)
階段二盒齿、main函數(shù)之后
main 開(kāi)始 到 第一個(gè)界面念逞。
打點(diǎn)困食,使用BLStopwatch.h和BLStopwatch.m這個(gè)類
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[BLStopwatch sharedStopwatch] start];
int a = 0;
for (int i = 0; i < 10000000; i++) {
a++;
}
[[BLStopwatch sharedStopwatch] splitWithDescription:@"didFinishLaunchingWithOptions"];
return YES;
}
- (void)viewDidLoad {
[super viewDidLoad];
//刷新時(shí)間:
[[BLStopwatch sharedStopwatch] refreshMedianTime];
int a = 0;
for (int i = 0; i < 10000000; i++) {
a++;
};
[[BLStopwatch sharedStopwatch] splitWithDescription:@"viewDidLoad"];
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
//刷新時(shí)間:
[[BLStopwatch sharedStopwatch] refreshMedianTime];
int a = 0;
for (int i = 0; i < 10000000; i++) {
a++;
};
[[BLStopwatch sharedStopwatch] splitWithDescription:@"viewDidAppear"];
[[BLStopwatch sharedStopwatch] stopAndPresentResultsThenReset];
}
二庵楷、二進(jìn)制重排
二進(jìn)制重排是在main函數(shù)之前
物理內(nèi)存
虛擬內(nèi)存 : 解決安全問(wèn)題塘匣、解決內(nèi)存使用率問(wèn)題
- 解決安全問(wèn)題:映射表(頁(yè)表)(虛擬頁(yè)表)
- 解決內(nèi)存使用率問(wèn)題:內(nèi)存分頁(yè)管理。缺頁(yè)中斷祈坠,然后加載到物理內(nèi)存叨咖,加載之前會(huì)簽名加載的頁(yè)瘩例;如果啟動(dòng)的時(shí)候要加載的代碼分別在不同的頁(yè),那么缺頁(yè)中斷時(shí)間就比較長(zhǎng)甸各,這時(shí)就出現(xiàn)了二進(jìn)制重排(把啟動(dòng)要加載的代碼放在前面幾頁(yè))垛贤。使用內(nèi)存分頁(yè)后,就會(huì)導(dǎo)致代碼的加載都是從0開(kāi)始的趣倾,為了防止黑客聘惦,就出現(xiàn)了ASLR。
內(nèi)存分頁(yè)技術(shù)
MacOS 儒恋、linux (4K為一頁(yè))
iOS(16K為一頁(yè))
PageFault(缺頁(yè)中斷)
1善绎、command+I5比勉、選擇Main Thread、選擇Virtual Memory驹止。File Backed Page in
就是PageFault
二進(jìn)制重排優(yōu)化是在鏈接階段對(duì)即將生成的可執(zhí)行文件進(jìn)行重新排列
order_file
1浩聋、打開(kāi)objc4-750
源碼
libobjc.order
存放的是方法的調(diào)用順序,可以用終端cat打開(kāi)2臊恋、Build Settings
中搜索order file
load方法的執(zhí)行順序
生成LinkMap文件
-
Build Settings
中搜索link map
,No改為Yes衣洁,然后Command+B
,build一下,就會(huì)生成LinkMap文件
打開(kāi)LinkMap文件
- Address: 函數(shù)真實(shí)實(shí)現(xiàn)的地址(匯編代碼的地址)(代碼的地址)
- Size:函數(shù)的大小抖仅,寫(xiě)的代碼的多與少
- File:所在文件
- Name: 方法名
-
0x0000000100d30000(ASLR)+00004848(偏移) = 0x100d34848
- 在
+[ViewController load]
方法里面打斷點(diǎn)坊夫,看到的地址和0x0000000100d30000(ASLR)+00004848(偏移) = 0x100d34848
相等,dis -s 0x100d34848
查看匯編代碼 -
0x100d34848
撤卢、0x100d3484c
环凿、0x100d34850
,這些是代碼的地址
添加dyz.order文件
-
在項(xiàng)目的根目錄創(chuàng)建一個(gè).order文件放吩,寫(xiě)入如下代碼
-
Build Settings
中搜索order file智听,添加dyz.order文件的地址(./dyz.order
或者${SRCROOT}/dyz.order
)
-
command + shift + k
清空一下緩存,command+B
編譯一下 -
再次查看LinkMap文件
Clang插莊
-
Build Settings
搜索 other c flags,添加-fsanitize-coverage=trace-pc-guard
參數(shù)
- 粘貼如下代碼到項(xiàng)目
extern "C" 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);
[圖片上傳中...(Snip20200420_13.png-54b663-1587378588681-0)]
for (uint32_t *x = start; x < stop; x++)
*x = ++N; // Guards should start from 1.
}
extern "C" 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);
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);
}
-
調(diào)試
暫停到推,然后附加考赛,然后x讀start內(nèi)存
讀頭x 0x10d4d7490
讀尾x 0x10d4d74c8-0x4
,讀尾需要減四個(gè)字節(jié)莉测,因?yàn)橐粋€(gè)方法占四個(gè)字節(jié)颜骤,而這個(gè)0x10d4d74c8
地址是尾方法結(jié)束的地址,所以如果需要讀尾方法的地址悔雹,就需要減掉四個(gè)字節(jié)
-
靜態(tài)插莊复哆!
所有方法、函數(shù)腌零、block 內(nèi)部都加入一行代碼梯找!調(diào)用__sanitizer_cov_trace_pc_guard
dis -s 0x00000001043e9a54
-
dis -s 0x00000001043e9a54-116
減去偏移值
拿到所有符號(hào)。導(dǎo)入
dlfcn.h
頭文件
#import "ViewController.h"
#import <dlfcn.h>
@interface ViewController ()
@end
@implementation ViewController
+(void)initialize
{
}
void(^block1)(void) = ^(void) {
};
void test(){
block1();
}
+(void)load
{
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
}
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);
Dl_info info;
dladdr(PC, &info);
printf("dli_fname:%s \n dli_fbase:%p \n dli_sname:%s \n dli_saddr:%p \n",info.dli_fname,info.dli_fbase,info.dli_sname,info.dli_saddr);
// char PcDescr[1024];
// __sanitizer_symbolize_pc(PC, "%p %F %L", PcDescr, sizeof(PcDescr));
// printf("guard: %p %x PC %s\n", guard, *guard, PcDescr);
}
@end
- while循環(huán)益涧,中會(huì)調(diào)用
__sanitizer_cov_trace_pc_guard
锈锤,會(huì)導(dǎo)致一直打印-[ViewController touchesBegan:withEvent:]
#import "ViewController.h"
#import <dlfcn.h>
#import <libkern/OSAtomic.h>
@interface ViewController ()
@end
@implementation ViewController
+(void)initialize
{
}
void(^block1)(void) = ^(void) {
};
void test(){
block1();
}
+(void)load
{
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
while (YES) {
SYNode * node = OSAtomicDequeue(&symbolList, offsetof(SYNode, next));
if (node == NULL) {
break;
}
Dl_info info;
dladdr(node->pc, &info);
printf("%s \n",info.dli_sname);
}
}
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.
}
//原子隊(duì)列
static OSQueueHead symbolList = OS_ATOMIC_QUEUE_INIT;
//定義符號(hào)結(jié)構(gòu)體
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};
//進(jìn)入
OSAtomicEnqueue(&symbolList, node, offsetof(SYNode, next));
}
@end
解決方法
Other C Flags
的參數(shù),等號(hào)后面加上func
,例如-fsanitize-coverage=func,trace-pc-guard
- 取反闲询、去重久免、函數(shù)符號(hào)前面添加下劃線(除了OC方法)、添加load
- 添加load:注銷
__sanitizer_cov_trace_pc_guard
中的if (!*guard) return;
,load的守衛(wèi)是0
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
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__]];
//將數(shù)組變成字符串
NSString * funcStr = [funcs componentsJoinedByString:@"\n"];
NSString * filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"dyz.order"];
NSData * fileContents = [funcStr dataUsingEncoding:NSUTF8StringEncoding];
[[NSFileManager defaultManager] createFileAtPath:filePath contents:fileContents attributes:nil];
NSLog(@"%@",filePath);
}
-
下載下來(lái)扭弧,顯示包內(nèi)容
-
項(xiàng)目中如果是OC和Swift混編
1阎姥、在Build Settings
搜索other swift flags
,如果是OC項(xiàng)目鸽捻,里面沒(méi)有Swift文件呼巴,那么搜索不到Other Swift Flags
,只有項(xiàng)目里面有了Swift文件才會(huì)搜索到御蒲。
2衣赶、添加參數(shù)-sanitize-coverage=func
和-sanitize=undefined
3、導(dǎo)入Swift頭文件#import "TraceDemo-Swift.h"
厚满,調(diào)用Swift方法[SwiftTest swiftTestLoad];
4府瞄、Swift方法同樣可以hook到
最后
- 把得到的
dyz.order
文件拷貝到項(xiàng)目的根目錄下。 -
Build Settings
中搜索order file碘箍,添加dyz.order文件的地址(./dyz.order
或者${SRCROOT}/dyz.order
) -
Build Settings
中搜索link map
,如果是Yes則改回No - 去掉 Other C Flags的參數(shù)
-fsanitize-coverage=func,trace-pc-guard
- 去掉 Other Swift Flags的參數(shù)
-sanitize-coverage=func
和-sanitize=undefined
- 注銷__sanitizer_cov_trace_pc_guard_init和__sanitizer_cov_trace_pc_guard方法
- 結(jié)束遵馆,打包上線