一个NSObject对象占用多少内存?

今天来聊聊NSObject对象占用多少内存的话题。

一.什么是NSObject对象?

NSObject *obj = [[NSObject alloc] init];这句代码中,obj是对象么?NONONO……很多人有这个误解,认为这个obj就是对象。正解:[[NSObject alloc] init]这个才是对象,obj是个指针,也就是obj指针指向的那片内存空间叫做对象。

二.对象本质是什么?

OC的底层是C和C++来实现的,那么可以猜测一下,这样一个复杂的的可以包含各种数据类型的集合,所对应的C的数据结构是什么呢?数组?字典?集合?结构体?
我们不烦大胆猜测一下……思索过后发现只有结构体大体符合,那么咱们来验证一下。
将含有下面的代码的main.m转成C++文件(main.cpp)
(定位到main.m,在终端输入指令xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp)

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSObject *obj = [[NSObject alloc] init];
    }
    return 0;
}

在main.cpp文件中发现了这样的一个结构体:

struct NSObject_IMPL {
    Class isa;
};

看见isa指针,就觉得好亲切。这说明了两个问题:

  • 每个对象的底层都是一个结构体
  • 每个对象内部都有一个isa指针

那么问题来了,64位下指针占用8个字节,那是不是一个对象占用8个字节的内存空间呢?答案显然不是。因为还有我们的成员变量啊,所以到此为止,得出结论:一个对象至少需要占用8个字节的内存空间来存放isa指针

此处介绍两个计算内存空间大小的方法:

  • runtime 中的class_getInstanceSize()
    *(return The size in bytes of instances of the class,返回一个类的实例对象的大小,其实就是底层结构体的大小)
  • malloc_size()
    (获得对象所开辟空间的大小)
    一个NSObject对象占用多少内存?_第1张图片
    image.png

    由上图可以看出,结构体大小为8个字节,但是系统给它分配了16个字节。

三.自定义一个继承于NSObject的类,研究实例对象的内存空间

1.场景一

@interface Dog :NSObject{
    @public
    int _age;
    int _height;
}
@end

新建一个Dog类继承于NSObject,按上述操作转化成c++代码。得到:

struct Dog_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    int _age;
    int _height;
};

猜测:struct NSObject_IMPL 结构体里边只有一个isa指针,占用8个字节。int类型在64位下,占用4个字节。那么这个Dog对象占用8+4+4=16个字节。
提醒:在计算的时候要注意一个问题:结构体的内存对齐

我们分别用class_getInstanceSize()和malloc_size()方法验证一下。


一个NSObject对象占用多少内存?_第2张图片
场景一测试

2.场景二

给Dog类在添加一个int成员变量,如下

@interface Dog :NSObject{
    @public
    int _age;
    int _height;
    int _weight;
}

猜测:struct NSObject_IMPL 结构体里边只有一个isa指针,占用8个字节。int类型在64位下,占用4个字节。根据内存对齐原则,那么这个Dog对象占用8+4+4+8=24个字节。

继续用上述方法,测试内存,如下


一个NSObject对象占用多少内存?_第3张图片
场景二测试

疑问:为什么会出现32呢?
解答:根据上边对两个计算内存方法的解释:
class_getInstanceSize():说白了就是计算结构体所占内存的大小;
malloc_size():计算对象所开辟的内存空间的大小;
一个是理论计算,一个是实际大小。为什么会出现这样的差距呢?这就是系统框架的限制。此处不做深入研究。

四.方法的内存都跑到哪里去了?

对于这个东西,请大家看我的另一篇对于oc方法的论述。现在只需要知道,一个实例(instance)对象中不存储方法。
传送门:

五.总结

结论:
1.一个NSObject对象,系统分配了16个字节的空间,但是实际上用了8个字节的空间
2.一个实例对象的内存空间=它的底层结构体的内存大小+系统框架给的限定
3.实例对象的内存中不包括方法的内存

你可能感兴趣的:(一个NSObject对象占用多少内存?)