【问题标题】:Empty Swift string Memory allocation Layout (Stack/ Heap allocation)空 Swift 字符串内存分配布局(堆栈/堆分配)
【发布时间】:2025-04-11 04:20:02
【问题描述】:

在 swift 中,字符串是结构类型,因此值将存储在堆栈内存而不是堆内存中。

假设我们声明了一个字符串:

let a = ""
let b = "o"

这是一个空字符串,但分配了一些内存。我需要知道分配给空字符串和假设为 1 的字符串的内存有什么区别。


如果我们说:-

var str:String?
var str: String = ""

通过绘图对内存布局的差异是我需要看到的。 (堆栈/堆)。

我试图在 google 上找到这个,但我在任何地方都找不到它的内存布局。

【问题讨论】:

  • 不是与 Objective-c 相关的问题。请删除标签
  • @Roee84 我想以直观的方式看到这一点。在堆栈/堆内存方式中,我认为这不是您标记为重复的问题

标签: swift string memory-management


【解决方案1】:

据我所知,strings 在 swift 中具有值类型语义和许多优化(写入时复制等),但在后台它们被桥接到 NSString 类,因此它们被分配在堆上。

值类型语义意味着从 swift 程序员的角度来看,当我们将值分配给另一个变量或传递给方法时,它们会被复制(使用写时复制优化),我们可以在方法内改变值,并且源字符串不会受到影响,让关键字不允许突变(由编译器检查)等等。

我建议您观看 GOTO 2016 会议上的 Mike Ash Exploring Swift Memory Layout 演示。

【讨论】:

    【解决方案2】:

    众所周知,Strings 是 swift 中的值类型,而值类型变量存储在堆栈内存分配中。

    var str:String?
    var str1: String = ""
    

    在上述情况下,两者都消耗堆栈内存。在 str 中可以分配 nil 值,但在 str1 中您永远不会分配 nil 值。

    【讨论】:

      【解决方案3】:

      String 是一个非常复杂的野兽。它有许多不同的底层表示,包括:

      • 字符串字面量,作为常量存储在二进制文件中

      • 小字符串,最多可以在堆栈上存储 15 个 UTF-8 代码单元(至少在 x86 上)

      • “本机”字符串(即尚未桥接到 Objective-C 的字符串),存储在尾部分配的堆缓冲区中

      • 来自 Obj-C 的“外来”字符串,可以用标记指针或堆分配的 NSString 对象表示

      • “共享”字符串,可以将 Swift 字符串文字表示为堆分配的 Obj-C 对象

      如果您想深入了解细节,可以从StringObject.swift 开始,其中有一堆 cmet 解释了一些布局细节。

      回答关于你给出的例子的问题:


      let a = ""
      

      一个空字符串有a canonical small string representation,它内联存储在堆栈中。


      let b = "o"
      

      字符串文字作为常量存储在二进制文件中。因此不需要堆分配——只需要一个指向二进制字符串地址的指针。

      但即使这不是一个常量字符串,例如它是由以下人员创建的:

      let o = "O".lowercased()
      

      那么它仍然可以表示为一个小字符串,内联存储在堆栈中。


      var str: String?
      

      String 具有 an extra inhabitant(至少在 x86 上),这意味着 String? 可以与 String 共享相同的布局。 nil 的值由额外的居民位模式之一表示。

      但即使String 没有额外的居民,也不需要额外的堆分配来代表String? 而不是String——它只需要额外的内联存储位。

      【讨论】: