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】:好的,我做了很多实验,终于弄明白了。
-
我们可以使用
&
来获取数组地址,因为一旦我们这样做了,Swift 将复制数组以更好地与C 交互,使用&
获取与数组相邻的对象的地址并进行数学运算。 或者使用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 的写时复制行为?的主要内容,如果未能解决你的问题,请参考以下文章
再谈QVector与QByteArray——Qt的写时复制(copy on write)技术