iOS【进阶】性能优化(上篇)
一、内存五大区
内存区域 |
特点 |
栈区 |
由编译器自动完成分配和释放,不需要程序员手动管理,主要存储了函数的参数和局部变量值等 |
堆区 |
需要程序员手动开辟并管理内存(OC有ARC,OC对象通常不需要程序员考虑释放问题) |
BSS段(全局区)(静态区) |
程序运行过程内存的数据一直都在,程序结束后由系统释放 |
常量区(数据段) |
专门用于存放常量,程序结束后由系统释放 |
程序代码区 |
用于存放程序运行时的代码,代码会被编译成二进制存进内存的程序代码区 |
下面我们来用代码验证一下:
1 #import <UIKit/UIKit.h> 2 #import "AppDelegate.h" 3 4 // BSS段 5 int g1; 6 static int s1 ; 7 8 //数据段 9 int g2 = 0; 10 static int s2 = 0; 11 12 int main(int argc, char * argv[]) { 13 @autoreleasepool { 14 15 //栈区 16 int i = 10; 17 int j = 10; 18 NSObject *objc = [NSObject new]; 19 20 NSLog(@"%p",&i); 21 NSLog(@"%p",&j); 22 NSLog(@"%p",&objc); 23 24 25 //堆区 26 NSObject *obj1 = [NSObject new]; 27 NSObject *obj2 = [NSObject new]; 28 NSObject *obj3 = [NSObject new]; 29 30 NSLog(@"%p",obj1); 31 NSLog(@"%p",obj2); 32 NSLog(@"%p",obj3); 33 34 35 //BSS段 36 NSLog(@"%p",&g1); 37 NSLog(@"%p",&s1); 38 39 40 //数据段 41 NSLog(@"%p",&g2); 42 NSLog(@"%p",&s2); 43 44 45 return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 46 } 47 }
打印结果:
2018-09-21 14:14:21.841008+0800 内存管理[1837:252099] 0x7fff527b711c // int 4个字节
2018-09-21 14:14:21.842005+0800 内存管理[1837:252099] 0x7fff527b7118 // int 4个字节
2018-09-21 14:14:21.842269+0800 内存管理[1837:252099] 0x7fff527b7110 // 指针 8个字节
2018-09-21 14:14:21.842630+0800 内存管理[1837:252099] 0x60400001f2e0
2018-09-21 14:14:21.842829+0800 内存管理[1837:252099] 0x60400001f360
2018-09-21 14:14:21.843044+0800 内存管理[1837:252099] 0x60400001f320
2018-09-21 14:14:21.843236+0800 内存管理[1837:252099] 0x10d44afcc
2018-09-21 14:14:21.843410+0800 内存管理[1837:252099] 0x10d44afd0
2018-09-21 14:14:21.843548+0800 内存管理[1837:252099] 0x10d44afc8
2018-09-21 14:14:21.843698+0800 内存管理[1837:252099] 0x10d44afd4
总结:
(1)栈区和堆区是运行时分配的内存,其他区是编译时分配的;
(2)栈区的地址是连续的,并且是由高到低分配的;
(3)堆区的地址是不连续的,堆区的访问速度没有栈区快,堆区的地址比栈区的小;
二、Tagged Pointer
(1)Tagged Pointer 专门用来存储小的对象,例如 NSNumber 和NSDate。
(2)Tagged Pointer 指针的值不再是地址了,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已!所以,它的内存并不存储在堆中,也不需要malloc和free。
(3)在内存读取速度快。
三、isa_t
四、散列表的原理
五、引用计数的存储
六、weak实现原理
1、弱引用对象,底层也是使用了哈希存储,或者叫散列存储,那么是对象的内存地址作为key,指向该对象的所有弱引用的指针作为值
2、释放时,就是以对象的内存地址作为key,去存储弱引用对象的哈希表里,找到所有的弱引用对象,然后设置为nil,最后移除这个弱引用的散列表