从底层原理看iOS中的三个内存操作:class_getInstanceSize&malloc_size&sizeof

59 阅读2分钟

本文源自本人的学习记录整理与理解,其中参考阅读了部分优秀的博客和书籍,尽量以通俗简单的语句转述。引用到的地方如有遗漏或未能一一列举原文出处还望见谅与指出,另文章内容如有不妥之处还望指教,万分感谢。

@interface Person : NSObject {
    int myIntVar;
    NSString *myStringVar;
}
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end

获取内存大小的方式

class_getInstanceSize

该方法是<objc/runtime>提供的api,其本质就是获取实例对象中成员变量的内存大小(采用8字节对齐)。 由于Objective-C是动态语言,一个对象的大小可能会随时改变,因此该函数返回的大小值也可能会随时改变

源码探索

class_getInstanceSize的执行流程图

graph LR
class_getInstanceSize --> alignedInstanceSize --> unalignedInstanceSize --> word_align

通过iOS开源的objc4源码来分析其底层实现

#ifdef __LP64__
#   define WORD_MASK 7UL
#else
#   define WORD_MASK 3UL
#endif

size_t class_getInstanceSize(Class cls) {
    if (!cls) return 0;
    return cls->alignedInstanceSize();
}

uint32_t alignedInstanceSize() const {
    return word_align(unalignedInstanceSize());
}

// 获取未对齐的类的内存大小即所有成员变量所占内存
uint32_t unalignedInstanceSize() const {
    return data()->ro()->instanceSize;
}

// 采用8字节对齐
static inline uint32_t word_align(uint32_t x) {
    return (x + WORD_MASK) & ~WORD_MASK;
}

实例

size_t size = class_getInstanceSize([Person class]);
NSLog(@"The size of Person instance is %zu bytes.", size);

// 打印结果: The size of Person instance is 40 bytes.
// 计算未对齐的类的内存大小 unalignedInstanceSize: 
// isa + int + NSString + NSString + NSInteger = 8 + 4 + 8 + 8 + 8 = 36
// 字节对齐 word_align(36): (36 + 7) & ~7 = 43 & ~7 = 40

malloc_size

用于获取指针指向的内存块的大小,其本质获取系统实际分配的内存大小(采用16字节对齐)

size_t mallocSize = malloc_size(( **__bridge** **const** **void***)p);
NSLog(@"The size of allocated memory is %zu bytes.\n", mallocSize);

// 打印结果: The size of allocated memory is 48 bytes.

sizeof

  1. C 语言中的一种运算符,用于返回一个数据类型所占用的内存大小
  2. class_getInstanceSize 方法不同的是,sizeof 运算符返回的是指定数据类型本身的大小,与该类型的对象实例是否已经被分配内存无关
  3. 在编译器的编译阶段就已确定大小,而非运行时确定

语法格式

sizeof(<#expression-or-type#>)

其中,参数expression-or-type可以是任何一个合法的表达式或数据类型,包括基本数据类型、结构体、联合体、数组和指针等。其返回值是一个size_t类型的无符号整数,表示所计算的数据类型或表达式所占据的内存大小,单位是字节。

实例

size(8+8)          // 打印结果:1, 8+8=16为Int类型,占4个字节
sizeof(YES)        // 打印结果: 1, YES为bool类型,占1个字节
sizeof(NSString *) // 打印结果: 8, 字符串占8个字节 
sizeof(person)     // 打印结果: 8, person为自定义的对象,本质是结构体指针,占8个字节