OC源码下载地址:opensource.apple.com/tarballs/ob…
一、内存大小
- iOS系统分配内存的原则一:分配的内存大小至少16字节
获取系统给OC对象实际分配的内存大小:malloc_size(需#import <malloc/malloc.h>)
NSLog(@"%zd", malloc_size((__bridge const void *)(obj)));
从NSObject的底层实现代码可以看出,NSObject是一个结构体,里面有一个指针成员(指针在64位系统占8字节,在32位系统占4字节),因此一个NSObject对象占8字节。
问:一个NSObject对象占多大内存?
答:iOS系统给NSObject对象分配16字节的内存,但是在64bit环境下,NSObject对象只使用8字节。
- iOS系统分配内存的原则二:分配的内存大小是16的倍数
一个Student类继承自NSObject,有3个int类型的成员:
获取类的成员变量的实际使用的内存大小:class_getInstanceSize(需#import <objc/runtime.h>)
NSLog(@"成员变量的内存大小:%zd", class_getInstanceSize([Student class]));
打印结果是24字节,由于这个原则,iOS系统会给Student对象分配32字节,而实际只使用24字节。
- 结构体的内存对齐原则:结构体的大小必须是最大成员变量大小的倍数
如上图,这个结构体的大小必须是8的倍数,也是就是16。
-
分配的内存大小至少16字节的验证过程
-
分配的内存大小是16的倍数的验证过程
malloc源码下载地址:opensource.apple.com/tarballs/li…
分配内存的函数调用流程:
(objc源码)allocWithZone: --> _objc_rootAllocWithZone --> class_createInstance --> _class_createInstanceFromZone --> malloc_zone_calloc
(libmalloc源码) malloc_zone_calloc --> nano_calloc(从ptr = zone->calloc(zone, num_items, size);推断出,可能不正确) --> _nano_malloc_check_clear --> segregated_size_to_fit
segregated_size_to_fit函数如下:
代码解析:
SHIFT_NANO_QUANTUM:16
SHIFT_NANO_QUANTUM:4
假设传入24,计算过程如下:
24+16-1 = 39
39的二进制: 0010 0111
往右移4位(>>4): 0000 0010 (后面的被舍弃)
往左移4位(<<4): 0010 0000 == 2^5 == 32
先把size+16-1,使其大于16,然后往右移4位(移除那些十进制值小于16的位),再往左移4位,得到 16的倍数(前面四位的值都是16的倍数),整个操作的目的就是得到比该值大,并且是16倍数的值。
所以得出结论:iOS中分配内存的大小是16的倍数。
- 查看某种类型占多大内存:sizeof
如:sizeof(int)
二、LLDB命令
LLDB的Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能。
- 常用指令
- p:打印(print的缩写)
- po:打印对象(print object的缩写)
- memory read:读取内存(简写:x)
-
- 使用:x/数量+格式+字节数 对象的内存地址
如:x/3xw 0x10010,表示:读取0x10010对象的内存(x),以16进制(x)格式输出3条数据(3),每条数据长度是4字节(w)。
-
- 格式说明:x:16进制,f:浮点,d:10进制
- 字节大小说明:b:byte 1字节,h:half word 2字节, w:word 4字节,g:giant word 8字节
- memory write:修改内存的值
使用:memory write 0x10012 10,表示修改0x10012内存地址的值为10
-
实操
-
在Xcode查看实例的内存布局
1个十六进制 == 4个二进制
十六进制:0x1111 1111 1111 1111
二进制:0b1111
2个十六进制 == 8个二进制(1位表示1个二进制) == 8位 == 1字节
前面8个字节被isa指针占用,后面8字节由于没有数据,初始化为0。