Swift 如何实现 Array 的写时复制行为?

Posted

技术标签:

【中文标题】Swift 如何实现 Array 的写时复制行为?【英文标题】:How Swift implement Array's copy-on-write behavior? 【发布时间】:2016-04-08 03:27:18 【问题描述】:

看完build better apps with value type。在他们制作的 Photoshop 示例中,他们说

在该图表的两个实例中唯一被复制的是包含该人衬衫的图块。因此,即使我有两个不同的文档,旧状态和新状态,但我必须使用的唯一新数据是此人衬衫中包含的瓷砖。

所以我开始想知道这两个数组在内存中的样子。所以我做了一个小实验。

struct Test 
    var i: Int
    var j: Int


var valueArray = [Test(i: 1, j: 9), Test(i: 2, j: 7)]
var valueArray2 = valueArray

当我打印 valueArray 和 valueArray2 的地址时,它们并不相同。 “也许他们通过在数组中存储指针来实现这一点?” 但是当我使用 lldb 打印内存内容时,它们实际上只是 4 Int (1,9,2,7)。 所以我很困惑,我什至还没有改变数组。他们似乎复制了整个数组?那我在哪里误会了? 我用来打印struct地址的函数是使用@nschum在this question中提供的方法。

func address(o: UnsafePointer<Void>) 
    let addr = unsafeBitCast(o, Int.self)
    print(NSString(format: "%p", addr))

这不是this question 的重复问题。我问的是语言羽毛,另一个是关于编程技巧。

【问题讨论】:

确实创建了新变量,但内部表示将是相同的,并且将在内部写入时被复制。开发人员无法访问值类型的内部实现细节。 How can I make a container with copy-on-write semantics? (Swift)的可能重复 这不是该问题的重复问题。我问的是语言羽毛,另一个是关于编程技巧。 【参考方案1】:

好的,我做了很多实验,终于弄明白了。

    我们可以使用&amp; 来获取数组地址,因为一旦我们这样做了,Swift 将复制数组以更好地与C 交互,使用&amp; 获取与数组相邻的对象的地址并进行数学运算。 或者使用lldb指令frame variable -L 一旦更改了任何值元素,就会复制整个数组。 Array 的实际值元素在堆上分配。 Swift 还对元素为类的 Array 做了很多优化。 Swift 很棒。

我实际上为此写了my first blog。

【讨论】:

在我看来,你所有的测试都是在操场上完成的,据我所知是这样解释的。所以这可能会改变,存储在内存中的方式。【参考方案2】:

在您的 cmets 并对此有了更好的了解后,我将其加载到操场上,它似乎按预期工作

原始答案供参考

要记住的是,结构基本上是内存中的数据块。当你创建 valueArray 时,一块内存被设置为它分配的值

当您创建 valueArray2 时,您正在创建结构的一个新实例,这意味着它将拥有一个全新的内存块,然后您将设置该新块的 内存到 valueArray 中内存块的相同 value。这会在两个不同的内存位置生成一份数据副本。

这与对象相反,在这种情况下 valueArray 将是指向一块内存的指针,而当您创建 valueArray2 时,它将创建一个指向同一块内存的新指针。

【讨论】:

这是我知道的,我期待一些优化,比如不复制 util write。 您希望他们优化什么?使用值类型的要点是副本之间不以任何方式相互关联。这要求它们位于不同的位置。 Multiple copies of an array share the same storage as long as none of the copies are modified. 来自Array Structure Reference 根据 WWDC 视频,只有数组中发生变化的元素才会被复制。 嗯...有趣。没有意识到这一点!我会假设每个变量仍然有它自己的内存地址,我希望调试器无论如何都会向你显示它的值。您是否尝试过打印数组中包含的结构的内存位置?

以上是关于Swift 如何实现 Array 的写时复制行为?的主要内容,如果未能解决你的问题,请参考以下文章

在Swift结构体中如何实现写时复制?

带有 APFS 的 macOS:终端中的写时复制

再谈QVector与QByteArray——Qt的写时复制(copy on write)技术

再谈QVector与QByteArray——Qt的写时复制(copy on write)技术

Linux 0.11-写时复制-30

Linux 0.11-写时复制-30