一文读懂 - Swift 和 Objective-C 创建对象时内存分配机制

在 iOS 开发中,Swift 和 Objective-C 创建对象时内存分配机制有显著差异。以下从底层原理、内存布局和实际分配角度详细分析:


一、Swift 对象内存分配

1. 核心特点

  • 最小分配单位 :Swift 对象默认最小分配 16 字节(64 位系统)

  • 内存布局

    swift

    复制代码
    | 8 字节 Metadata 指针 | 8 字节 RefCount(引用计数) | 实例变量... |
  • 空类(无属性)实例:固定 16 字节(Metadata + RefCount)

2. 内存增长规则

  • 属性增加 :每新增一个属性,按 8 字节对齐增长
  • 继承影响:父类属性优先布局,子类属性在后

3. 验证示例

swift

php 复制代码
class EmptyClass {} // 空类
print(class_getInstanceSize(EmptyClass.self)) // 输出:16

class MyClass {
    var id: Int = 0     // Int = 8 字节
    var flag: Bool = true // Bool = 1 字节(对齐到 8)
}
print(class_getInstanceSize(MyClass.self)) // 输出:32

计算过程

  • Metadata 指针:8 字节
  • RefCount:8 字节
  • id: Int:8 字节
  • flag: Bool:实际 1 字节 → 对齐填充后占 8 字节
  • 总计:8 + 8 + 8 + 8 = 32 字节

💡 系统实际调用 malloc 时可能分配 32/48/64 字节(系统内存块粒度),但对象自身仅使用对齐后的部分。


二、Objective-C 对象内存分配

1. 核心特点

  • 最小分配单位 :固定包含 isa 指针(8 字节

  • 内存布局

    objc

    复制代码
    | 8 字节 isa 指针 | 实例变量... |
  • 空类(继承自 NSObject)实例:8 字节 (仅 isa

2. 内存增长规则

  • 属性/IVars :按声明顺序排列,遵循 8 字节对齐
  • 无额外 RefCount:引用计数存储在全局 Side Table

3. 验证示例

objc

less 复制代码
@interface EmptyObjCClass : NSObject
@end
@implementation EmptyObjCClass
@end
NSLog(@"%zu", class_getInstanceSize([EmptyObjCClass class])); // 输出:8

@interface MyObjCClass : NSObject
@property (nonatomic, assign) NSInteger id; // long = 8 字节
@property (nonatomic, assign) BOOL flag;    // BOOL = 1 字节
@end
NSLog(@"%zu", class_getInstanceSize([MyObjCClass class])); // 输出:24

计算过程

  • isa 指针:8 字节
  • id: NSInteger:8 字节
  • flag: BOOL:实际 1 字节 → 对齐填充后占 8 字节
  • 总计:8 + 8 + 8 = 24 字节

💡 系统通过 alloc 分配时实际调用 malloc_zone_calloc,可能分配 16/32 字节 的内存块。


三、关键差异对比

特性 Swift Objective-C
元数据指针 Metadata (8 字节) isa (8 字节)
引用计数存储 对象内嵌 RefCount (8 字节) 全局 Side Table
空类最小大小 16 字节 8 字节
内存对齐 8 字节对齐 8 字节对齐
继承影响 父类属性优先布局 父类属性优先布局
系统分配实际大小 16/32/48 字节(内存块粒度) 16/32 字节(内存块粒度)

四、底层原理深入

1. Swift 的 RefCount 设计

  • 内嵌在对象头部的 Inline RefCount
  • 支持 强引用/弱引用计数 快速操作
  • 溢出时降级到 Side Table

2. Objective-C 的 isa 优化

  • isa 指针使用 non-pointer isa
  • 低比特位存储:引用计数标志、析构状态等
  • 节省全局表空间,提高访问效率

3. 系统分配策略

  • 实际调用 malloc_size 返回的大小总是 16 的倍数

  • 示例:

    swift

    scss 复制代码
    let obj = MyClass()
    print(malloc_size(Unmanaged.passUnretained(obj).toOpaque())) 
    // 可能输出:48(实际分配) vs 32(对象自身)

五、优化建议

  1. 减少小对象创建:尤其 Swift 有 16 字节最小开销

  2. 属性顺序优化

    swift

    kotlin 复制代码
    // 劣:占 40 字节(8+1 → 对齐后 8+8)
    class Bad {
        var a: Int8 = 0
        var b: Int = 0
    }
    
    // 优:占 24 字节(8+8 → 对齐后 16)
    class Good {
        var b: Int = 0
        var a: Int8 = 0
    }
  3. 值类型优先 :结构体(struct)无额外开销,栈分配


总结

  • Swift 对象:基础成本更高(16 字节起),适合复杂对象
  • Objective-C 对象:更轻量(8 字节起),但依赖全局表
  • 实际分配 :系统总是分配 ≥ 计算大小 的内存块(16 字节粒度)

理解这些差异有助于优化内存敏感场景(如高频创建对象),在 Swift 中合理使用值类型可显著提升性能。

相关推荐
2501_9160088912 小时前
iOS 发布全流程详解,从开发到上架的流程与跨平台使用 开心上架 发布实战
android·macos·ios·小程序·uni-app·cocoa·iphone
非专业程序员14 小时前
iOS/Swift:深入理解iOS CoreText API
ios·swift
shayudiandian14 小时前
JavaScript性能优化实战
开发语言·javascript·性能优化
某柚啊14 小时前
iOS移动端H5键盘弹出时页面布局异常和滚动解决方案
前端·javascript·css·ios·html5
DemonAvenger15 小时前
深入浅出 Redis 布隆过滤器:从原理到实战,10 年经验总结
数据库·redis·性能优化
xingxing_F16 小时前
Swift Publisher for Mac 版面设计和编辑工具
开发语言·macos·swift
earthzhang20211 天前
第3讲:Go垃圾回收机制与性能优化
开发语言·jvm·数据结构·后端·性能优化·golang
apocelipes1 天前
golang unique包和字符串内部化
java·python·性能优化·golang
RollingPin1 天前
iOS八股文之 RunLoop
ios·多线程·卡顿·ios面试·runloop·ios保活·ios八股文
2501_916007471 天前
iOS 混淆工具链实战,多工具组合完成 IPA 混淆与加固(iOS混淆|IPA加固|无源码混淆|App 防反编译)
android·ios·小程序·https·uni-app·iphone·webview