前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一个NSObject对象占用多少个字节

一个NSObject对象占用多少个字节

原创
作者头像
ruochen
修改2021-11-22 13:50:24
6740
修改2021-11-22 13:50:24
举报
文章被收录于专栏:若尘的技术专栏
  • Objective-C中,我们可以通过一些方法来获取一个NSObject对象占用多少字节
  • 代码获取NSObject实例对象的成员变量字节大小
代码语言:txt
复制
* 获取一个NSObject实例对象的成员变量所占用的字节大小,可以用`runtime`的api, `class_getInstanceSize`来获取,得到`8`
代码语言:txt
复制
    /** 
代码语言:txt
复制
 * Returns the size of instances of a class.
 * 
 * @param cls A class object.
 * 
 * @return The size in bytes of instances of the class \e cls, or \c 0 if \e cls is \c Nil.
 */
OBJC_EXPORT size_t
class_getInstanceSize(Class _Nullable cls) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
代码语言:txt
复制
* 也可以通过`malloc`库里的api,`malloc_size`来获取,得到`16`
代码语言:txt
复制
    extern size_t malloc_size(const void *ptr);
代码语言:txt
复制
/* Returns size of given ptr */
  • 下面是实战代码
代码语言:txt
复制
#import <Foundation/Foundation.h>
代码语言:txt
复制
#import <objc/runtime.h>
代码语言:txt
复制
#import <malloc/malloc.h>
代码语言:txt
复制
// NSObject Implementation
代码语言:txt
复制
struct NSObject_IMPL {
代码语言:txt
复制
    Class isa; // 8个字节
代码语言:txt
复制
};
代码语言:txt
复制
// 指针
代码语言:txt
复制
// typedef struct objc_class *Class;
代码语言:txt
复制
int main(int argc, const char * argv[]) {
代码语言:txt
复制
    @autoreleasepool {
代码语言:txt
复制
        NSObject *obj = [[NSObject alloc] init];
代码语言:txt
复制
        // 16个字节
代码语言:txt
复制
        // 获得NSObject实例对象的成员变量所占用的大小 >> 8
代码语言:txt
复制
        NSLog(@"%zd", class_getInstanceSize([NSObject class]));
代码语言:txt
复制
        // 获得obj指针所指向内存的大小 >> 16
代码语言:txt
复制
        NSLog(@"%zd", malloc_size((__bridge const void *)obj));
代码语言:txt
复制
        // 什么平台的代码
代码语言:txt
复制
        // 不同平台支持的代码肯定是不一样
代码语言:txt
复制
        // Windows、mac、iOS
代码语言:txt
复制
        // 模拟器(i386)、32bit(armv7)、64bit(arm64)
代码语言:txt
复制
        // 可以通过 命令行工具,生成C++文件
代码语言:txt
复制
        // xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
代码语言:txt
复制
        // 然后把编译成功的cpp文件,拖入到工程中,注意 Copy items if needed 不勾选
代码语言:txt
复制
        // 然后Build Phases中删除main-arm64.cpp编译选项(选中文件点减号或按delete键)
代码语言:txt
复制
        // 这样文件不参与编译就不会报错了
代码语言:txt
复制
    }
代码语言:txt
复制
    return 0;
代码语言:txt
复制
}
  • 通过生成的编译代码,我们知道了NSObject对象本质上是C++结构体,结构大概长这样
代码语言:txt
复制
// NSObject Implementation
代码语言:txt
复制
struct NSObject_IMPL {
代码语言:txt
复制
    Class isa; // 8个字节
代码语言:txt
复制
};

通过objc源码实现一探究竟

  • 现在苹果的一些底层库的核心实现源码已经开放,我们可以去官网下载
代码语言:txt
复制
* 地址`https://opensource.apple.com/tarballs/objc4/`
* 选择版本号最新的下载查看查看源码发现,一旦发现
代码语言:txt
复制
inline size_t instanceSize(size_t extraBytes) const {
代码语言:txt
复制
        if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
代码语言:txt
复制
            return cache.fastInstanceSize(extraBytes);
代码语言:txt
复制
        }
代码语言:txt
复制
        size_t size = alignedInstanceSize() + extraBytes;
代码语言:txt
复制
        // CF requires all objects be at least 16 bytes.
代码语言:txt
复制
        if (size < 16) size = 16;
代码语言:txt
复制
        return size;
代码语言:txt
复制
    }
  • CoreFoundation框架里的硬性规定,内存对齐,小于16就会设置为16

用Xcode打断点看内存结构

  • 打上断点

image.png

  • Xcode菜单栏选中Debug -> Debug Workflow -> View Memory

image.png

  • 看到的内存结构如下图所示

image.png

  • 也可以用常用的LLDB指令查看

image.png

  • 看到的打印如下图所示

image.png

总结

  • 一个NSObject对象占用多少字节

回答

  1. 系统分配了16个字节给NSObject对象(通过malloc_size函数获得)
  2. 但是NSObject对象内部只使用了8个字节的空间(64bit环境下,可以通过class_getInstanceSize函数来获取),其实就是isa

扩展到有继承结构的对象

  • Student继承自NSObject
  • 代码结构如下
代码语言:txt
复制
struct Student_IMPL {
代码语言:txt
复制
    Class isa;
代码语言:txt
复制
    int _no;
代码语言:txt
复制
    int _age;
代码语言:txt
复制
};
代码语言:txt
复制
@interface Student : NSObject
代码语言:txt
复制
{
代码语言:txt
复制
    @public
代码语言:txt
复制
    int _no;
代码语言:txt
复制
    int _age;
代码语言:txt
复制
}
代码语言:txt
复制
@end
代码语言:txt
复制
@implementation Student
代码语言:txt
复制
@end
代码语言:txt
复制
int main(int argc, const char * argv[]) {
代码语言:txt
复制
    @autoreleasepool {
代码语言:txt
复制
        Student *stu = [[Student alloc] init];
代码语言:txt
复制
        stu->_no = 4;
代码语言:txt
复制
        stu->_age = 5;
代码语言:txt
复制
        // 16
代码语言:txt
复制
        NSLog(@"%zd", class_getInstanceSize([Student class]));
代码语言:txt
复制
        // 16
代码语言:txt
复制
        NSLog(@"%zd", malloc_size((__bridge const void *)stu));
代码语言:txt
复制
        struct Student_IMPL *stuImpl = (__bridge struct Student_IMPL *)stu;
代码语言:txt
复制
        // no is 4, age is 5
代码语言:txt
复制
        NSLog(@"no is %d, age is %d", stuImpl->_no, stuImpl->_age);
代码语言:txt
复制
    }
代码语言:txt
复制
    return 0;
代码语言:txt
复制
}
  • 大概的内存结构图

image.png

扩展到有多重继承的结构

  • 如下图继承结构
代码语言:txt
复制
@interface Person: NSObject
代码语言:txt
复制
{
代码语言:txt
复制
    int _age;
代码语言:txt
复制
}
代码语言:txt
复制
@end
代码语言:txt
复制
@implementation Person
代码语言:txt
复制
@end
代码语言:txt
复制
@interface Student : Person
代码语言:txt
复制
{
代码语言:txt
复制
    int _no;
代码语言:txt
复制
}
代码语言:txt
复制
@end
代码语言:txt
复制
@implementation Student
代码语言:txt
复制
@end
代码语言:txt
复制
int main(int argc, const char * argv[]) {
代码语言:txt
复制
    @autoreleasepool {
代码语言:txt
复制
        Person *person = [[Person alloc] init];
代码语言:txt
复制
        // 16
代码语言:txt
复制
        NSLog(@"person --- %zd", class_getInstanceSize([Student class]));
代码语言:txt
复制
        // 16
代码语言:txt
复制
        NSLog(@"person --- %zd", malloc_size((__bridge const void *)person));
代码语言:txt
复制
        Student *stu = [[Student alloc] init];
代码语言:txt
复制
        // 16
代码语言:txt
复制
        NSLog(@"stu --- %zd", class_getInstanceSize([Student class]));
代码语言:txt
复制
        // 16
代码语言:txt
复制
        NSLog(@"stu --- %zd", malloc_size((__bridge const void *)stu));
代码语言:txt
复制
    }
代码语言:txt
复制
    return 0;
代码语言:txt
复制
}
  • 结构如下

image.png

  • 一个Person对象,一个Student对象占用多少内存空间?
  • 答案是,都是16
  • 大概的内存结构图

image.png

  • 有内存对齐的原因,结构体的大小必须是最大成员大小(16)的倍数

Objective-C不同数据类型占用字节大小

  • 可以通过sizeof来获取不同数据类型占用字节大小
  • sizeof其实不是一个函数,仅仅只是一个操作运算符罢了,编译时就确定了的

类型

32位机器

64位机器

BOOL

1

1

bool

1

1

int

4

4

short

2

2

long

4

8

long long

8

8

NSInteger

4

8

float

4

4

double

8

8

CGFloat

4

8

char

1

1

指针地址

4

8

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
目录
  • 通过objc源码实现一探究竟
  • 用Xcode打断点看内存结构
  • 总结
    • 回答
    • 扩展到有继承结构的对象
    • 扩展到有多重继承的结构
      • Objective-C不同数据类型占用字节大小
      相关产品与服务
      命令行工具
      腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档