Runtime-OC对象的内存
2019-05-03 本文已影响6人
cyh老崔
一. NSObject对象分配内存大小
有两个方法可以得到一个指针对象的大小:
-
class_getInstanceSize(Class _Nullable cls)
: 得到编译器计算的大小, 即实际使用的大小 -
size_t malloc_size(const void *ptr)
: 得到实际分配的堆内存大小
#import <objc/runtime.h>
#include <malloc/malloc.h>
NSObject *obj= [NSObject new];
size_t size1 = class_getInstanceSize([NSObject class]);
size_t size2 = malloc_size((__bridge void *)obj);
NSLog(@"size1 = %zd, size2 = %zd", size1, size2);
输出:
size1 = 8, size2 = 16
可看到实际分配的堆内存大小>实际使用的内存大小
ref: https://forums.developer.apple.com/thread/114963
问题: oc为什么这样设计呢? 猜测:
- 备用空间
- 为什么是2倍? 正如方法缓存, 扩充时都是扩充一倍
二. 类对象组成
- 定义一个简单的类:
@interface Boy : NSObject
{
@public
int _weight;
}
@end
@implementation Boy
@end
- clang下:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
为什么指定生成cpp文件呢? 因为oc底层即cpp, 以免生成文件过大
生成文件中, 相关代码如下:
struct Boy_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _weight;
};
struct NSObject_IMPL {
Class isa;
};
即类Boy
即Boy_IMPL
结构体, 而Boy_IMPL
结构体中包含下面两个成员变量:
Class isa; //每个对象都有的隐藏成员变量
int _weight; //其它定义的成员变量
2.1 体现在NSObject与Boy对象的内存大小如下:
size_t objSize = class_getInstanceSize(NSObject.class);
size_t boySize = class_getInstanceSize(boy.class);
NSLog(@"objSize: %zd, boySize: %zd", objSize, boySize);
输出:
objSize: 8, boySize: 16
可看到:
- 一个空的NSObject对象, 就有8个字节, 即isa指针的大小
- Boy对象的内存大小为16, 因为内存对齐, 所以Boy对象大小为8的倍数
2.2 体现在内存实际内容:
-
查看内存地址:
Boy对象地址 -
地址对应内存:
内存地址 -
arm是大端架构, 低位在高地址. 只查看自己的内存: 前16字节即可.
-
前8个字节是isa指针
-
后4个字节是0x42, 即66, 我们给
_weight
赋的值 -
最后4个字节是内存对齐空余出来的4个字节, 并已经初始化为0
2.3 LLDB
读取内存也可以看到这16字节的值