- 在
Objective-C中,我们可以通过一些方法来获取一个NSObject对象占用多少字节 - 代码获取
NSObject实例对象的成员变量字节大小
* 获取一个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 */- 下面是实战代码
#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的结构体,结构大概长这样
// NSObject Implementation代码语言:txt复制struct NSObject_IMPL {代码语言:txt复制 Class isa; // 8个字节代码语言:txt复制};通过objc源码实现一探究竟
- 现在苹果的一些底层库的核心实现源码已经开放,我们可以去官网下载
* 地址`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对象占用多少字节
回答
- 系统分配了
16个字节给NSObject对象(通过malloc_size函数获得) - 但是
NSObject对象内部只使用了8个字节的空间(64bit环境下,可以通过class_getInstanceSize函数来获取),其实就是isa
扩展到有继承结构的对象
Student继承自NSObject- 代码结构如下
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
扩展到有多重继承的结构
- 如下图继承结构
@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 |


