OC对象 - NSObject对象占用多少内存

OC对象 - NSObject对象占用多少内存

1 前言

我们知道NSOjcect底层实现中,struct NSObject_IMPL结构体里面仅有Class isa一个成员,那么,NSObject对象是否就是占用8个字节呢?
先说结果:一个NSObject对象占用的是16字节,但实际利用的只有 8 个字节

我们来验证一下

  • 本节我们主要会用到一下这两个函数 class_getInstanceSizemalloc_size
objectivec 复制代码
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSObject *obj = [[NSObject alloc] init];
        
        // 获得NSObject类的实例对象所占用的大小
        NSLog(@"%zd", class_getInstanceSize([NSObject class]));
        
        // 获得obj指针指向内存的大小
        NSLog(@"%zd", malloc_size((__bridge const void *)(obj)));
    }
    return 0;
}

我们分别用这两个函数,打印内存大小 class_getInstanceSize打印的是 8 字节,malloc_size 打印的是 16 字节

2 现象分析

  • 首先,class_getInstanceSize打印的是对象所占用的大小malloc_size打印的是指针所指向那块内存的大小
  • 所以,一个NSObject对象占用的是16字节,但实际利用的只有 8 个字节

3 源码分析

我们可以在https://github.com/apple-oss-distributions/objc4/tags下载到源码

  • 源码中我们可以找到如下
  • 最终分配内存的时候,如果 size<16,会直接分配16

4 实时查看内存数据

通过实时查看内存,再来验证一下

4.1 查看方式

  • 先打断点
  • Debug -> Debug Workflow -> View Memory
  • 赋值想要查看的内存地址,粘贴到 Address 文本框,回车

4.2 使用LLDB查看

4.3 常用LLDB命令

5 更复杂的继承结构

如果是存在继承关系的类,会是怎样的呢

主要有2条内存对其原则

  1. 内存分页对其,即16字节为一个页,因此内存分配的最小单位是16字节
  2. 结构体的内存分配大小为最大成员类型所占内存的倍数

5.1 Student类

  • 我们创建一个Studen类,继承与NSObject,然后增加自定义成员变量
objectivec 复制代码
@interface Studen : NSObject {
    @public
    int _no;
    int _age;
}
@end

@implementation Studen

@end
  • 这时候底层实现是这样的

  • 然后一样的打印

objectivec 复制代码
Studen *studen = [[Studen alloc] init];
        
        // 获得Studen类的实例对象所占用的大小
        NSLog(@"Studen实力对象:%zd", class_getInstanceSize([Studen class]));
        
        // 获得studen指针指向内存的大小
        NSLog(@"studen指向内存:%zd", malloc_size((__bridge const void *)(studen)));
  • 都为 16 了。
  • 我们在 NSObject 基础上,又声明了一个int类型的_no,一个int 类型的_age,int类型占用 4 个字节,2 个 int 就是 8 字节,加上 isa 的 8 字节,刚好就是 16 字节

5.2 此时的内存布局

5.3 再加上Person类

  • 这时候底层实现是这样的

  • 此时NSObject、Person、Studen三者的关系是

5.4 内存分配

我们再给Studen类加个int的属性,内存分配会是怎样的呢

less 复制代码
@interface Person : NSObject {
    @public
    int _age;
}

@end
@implementation Person

@end

@interface Studen : Person {
    @public
    int _no;
    int _class;
}
@end

@implementation Studen

@end
  • 上面提到2条内存对其原则,如果不清楚第二条规则存在的情况下
    • 8 + 4 + 4 + 4 = 20,得到的答案是,实例对象:20,实际分配内存 32。这和实际打印结果就不一样了
  • 实际上,因为结构体的内存分配大小为最大成员类型所占内存的倍数,所以实力对象所占内存应该是isa=8的倍数,所以对其后应该是24字节

5.5 查看内存信息

  • 子类的内存分布,会将父类的成员优先放在前面,然后按顺序排布
  • 中间如果有空余的未使用的,会优先使用。(比如Peerson类实际使用了12字节,但是Studen的第一个成员_no是从第13个字节开始的,而不会从第17个字节开始)

@oubijiexi

相关推荐
xuanzdhc4 小时前
Linux 基础IO
linux·运维·服务器
愚润求学4 小时前
【Linux】网络基础
linux·运维·网络
bantinghy5 小时前
Linux进程单例模式运行
linux·服务器·单例模式
小和尚同志5 小时前
29.4k!使用 1Panel 来管理你的服务器吧
linux·运维
帽儿山的枪手6 小时前
为什么Linux需要3种NAT地址转换?一探究竟
linux·网络协议·安全
shadon1789 天前
回答 如何通过inode client的SSLVPN登录之后,访问需要通过域名才能打开的服务
linux
小米里的大麦9 天前
014 Linux 2.6内核进程调度队列(了解)
linux·运维·驱动开发
算法练习生9 天前
Linux文件元信息完全指南:权限、链接与时间属性
linux·运维·服务器
忘了ʷºᵇₐ9 天前
Linux系统能ping通ip但无法ping通域名的解决方法
linux·服务器·tcp/ip
浩浩测试一下9 天前
渗透测试指南(CS&&MSF):Windows 与 Linux 系统中的日志与文件痕迹清理
linux·运维·windows·安全·web安全·网络安全·系统安全