【iOS】源码阅读(三)——内存对齐原理

打印 上一主题 下一主题

主题 1913|帖子 1913|积分 5739

媒介

  之前学习alloc相干源码,涉及到内存对齐的相干内容,今天笔者具体学习了一下相干内容并写了此篇博客。
获取内存大小的三种常用方式

  获取内存大小的方式有很多种,主要分为三类:获取对象实例占用的内存大小、获取历程占用的内存大小​​、获取数据布局/内存块的大小​。在iOS中获取内存大小的三种方式主要有:sizeof 、class_getInstanceSize 、malloc_size。
sizeof



  • 编译时运算符​​,返回变量或类型在内存中占用的字节数。
  • ​​只适用于​​根本数据类型(int、float)、布局体、类实例(仅计算静态分配的内存)。
  • 不适用于动态分配的内存(如通过 malloc 分配的部分)、对象头(如 Objective-C 的 isa 指针)。
  首先,需要明确,sizeof是一个操作数,不是函数;其次,这个大小在编译时就已经确定了,不考虑运行时的动态内存。对于OC对象,sizeof只返回指针的大小(通常环境下为8字节),而不是对象的现实占用内存。


%zu:
   一般用于输出或读取 size_t 类型(即无符号整型)的变量(通常是 sizeof 运算符的结果)。
  class_getInstanceSize



  • Objective-C 运行时函数​​,返回一个 Objective-C 类的实例对象在内存中占用的现实大小(不包括额外的 malloc 分配开销)。
  • ​​包含的内容:isa 指针(8 字节),所有实例变量(ivars)的大小,内存对齐填充。
  1. #import <objc/runtime.h>
  2. @interface MyClass : NSObject
  3. @property (nonatomic, strong) NSString *name; // 8 字节
  4. @property (nonatomic, assign) NSInteger age;  // 8 字节
  5. @end
  6. @implementation MyClass
  7. @end
  8. // 计算实例变量总大小
  9. size_t instanceSize = class_getInstanceSize([MyClass class]);
  10. NSLog(@"实例变量大小: %zu 字节", instanceSize);
复制代码

按理论来说,这里应该输出16个字节,但现实上输出为24个字节,这是为什么呢?
这里可以简单理解为class_getInstanceSize 遵循的是8字节对齐:
   每个 Objective-C 对象都有一个 isa 指针,指向它的类对象,这在 64 位系统上占用 8 字节。
在刚刚的代码中:
NSString *name:一个强引用的指针,占用 8 字节
NSInteger age:在 64 位系统上占用 8 字节
  以是刚才代码中的内存计算:isa (8) + name (8) + age (8) = 24 字节
以是总和是 24 字节(8 + 8 + 8),这正好是 8 字节对齐的倍数,不需要额外填充。假如这个类没有声明任何实例变量,大小会是 16 字节(8 字节的 isa 指针 + 8 字节的填充,以满意最小 16 字节的对象大小要求)。
至于为什么类没有声明任何实例变量,大小会是 16 字节:
   isa 指针占用 8 字节(所有 Objective-C 对象都有)。
Objective-C 运行时强制对象最小大小为 16 字节(即使没有实例变量),这是为了内存管理的效率(淘汰小对象的内存碎片)。剩余的 8 字节是 填充(padding),未被使用但必须分配。
  总结:
   class_getInstanceSize遵循8字节对齐。
24 字节 是 isa + name + age 的天然大小,不需要额外填充。
类没有声明任何实例变量,大小会是 16 字节。
  malloc_size



  • ​​C 标准库函数​​,返回 malloc(或 calloc/realloc)现实分配的内存块大小(可能比请求的大小更大),遵循16字节对齐。
  • 包含​​对象本身的大小(class_getInstanceSize 的结果)和 malloc 的内存管理开销(如内存对齐、内存池优化等)。
  1. int *array = malloc(10 * sizeof(int)); // 请求40字节
  2. size_t allocatedSize = malloc_size(array);
  3. printf("Malloc size: %zu\n", allocatedSize); // 输出为48(16字节对齐)
复制代码

相识到这里,我们就可以把 class_getInstanceSize和malloc_size拉在一起看看,我们在刚刚 class_getInstanceSize学习的代码里添加:
  1. size_t allocatedSize = malloc_size((__bridge const void *)obj);
  2. NSLog(@"malloc_size: %zu", allocatedSize); // 32
复制代码
这里会输出32,因为class_getInstanceSize 计算的是 24 字节,但 malloc 会 向上取整到近来的 16/32 字节,以是现实分配 32 字节:

总结

  先用代码来进行对比,我们可以看到输出结果:


  对三者进行总结如下:


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

铁佛

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表