当前位置: 首页 > news >正文

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

文章目录

  • 前言
  • 获取内存大小的三种常用方式
    • sizeof
    • class_getInstanceSize
    • malloc_size
  • 总结

前言

  之前学习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)的大小,内存对齐填充。
#import <objc/runtime.h>@interface MyClass : NSObject
@property (nonatomic, strong) NSString *name; // 8 字节
@property (nonatomic, assign) NSInteger age;  // 8 字节
@end@implementation MyClass
@end// 计算实例变量总大小
size_t instanceSize = class_getInstanceSize([MyClass class]);
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 的内存管理开销(如内存对齐、内存池优化等)。
int *array = malloc(10 * sizeof(int)); // 请求40字节
size_t allocatedSize = malloc_size(array);
printf("Malloc size: %zu\n", allocatedSize); // 输出为48(16字节对齐)

请添加图片描述
了解到这里,我们就可以把 class_getInstanceSize和malloc_size拉在一起看看,我们在刚刚 class_getInstanceSize学习的代码里添加:

size_t allocatedSize = malloc_size((__bridge const void *)obj);
NSLog(@"malloc_size: %zu", allocatedSize); // 32

这里会输出32,因为class_getInstanceSize 计算的是 24 字节,但 malloc 会 向上取整到最近的 16/32 字节,所以实际分配 32 字节:
请添加图片描述

总结

  先用代码来进行对比,我们可以看到输出结果:
在这里插入图片描述
在这里插入图片描述
  对三者进行总结如下:
请添加图片描述

http://www.xdnf.cn/news/314857.html

相关文章:

  • AGV导航控制器技术方案——基于EFISH-SBC-RK3576/SAIL-RK3576的国产化革新‌(新一代工业级自主可控解决方案)‌
  • 战术级微波干扰系统:成都鼎轻量化装备如何实现全频段智能压制?
  • 从字节到链接:用类型化数组生成神奇的对象 URL
  • 如何进行室内VR全景拍摄?
  • Android 有线网开发调试总结
  • 【计算机视觉】OpenCV实战项目:Long-Exposure:基于深度学习的长时间曝光合成技术
  • C26-冒泡排序法
  • Flutter——数据库Drift开发详细教程(五)
  • 二叉平衡树
  • 学习笔记:黑马程序员JavaWeb开发教程(2025.3.29)
  • Linux 驱动开发步骤及 SPI 设备驱动移植示例
  • 基于SpringBoot和PostGIS的应急运输事件影响分析-以1.31侧翻事故为例
  • Docker 容器镜像环境的依赖导出
  • Android 10.0 SharedPreferences in credential encrypted storage are not avai
  • 声波解码器:当40kHz遇见AIoT时代——超声波传感器的“隐形智慧”革命
  • 从明文裸奔到密钥长城:HTTPS加密全链路攻防与CA信任锚点构建
  • 【疑难杂症2025-003】Java-mvn项目在gitlab-ci构建镜像时遇到的问题和解决方案
  • 内网渗透技术全面指南——安全业务视角(基于《内网渗透技术 (吴丽进、苗春雨 主编;郑州、雷珊珊、王伦 副主编)》)
  • stm32常见错误
  • 矩阵扩展-算卷积算法介绍及C语言代码实现
  • Node.js vs 浏览器中的JavaScript:区别全解析
  • QT —— QWidget(2)
  • 【Science Advances】普林斯顿大学利用非相干光打造可重构纳米光子神经网络
  • 全文索引数据库Elasticsearch底层Lucene
  • SafeDrive:大语言模型实现自动驾驶汽车知识驱动和数据驱动的风险-敏感决策——论文阅读
  • 【Pandas】pandas DataFrame expanding
  • 常用设计模式在 Spring Boot 项目中的实战案例
  • 【LLM+Code】Devin PromptTools详细解读
  • 【spring】Spring、Spring MVC、Spring Boot、Spring Cloud?
  • 【Bootstrap V4系列】学习入门教程之 组件-折叠(Collapse)