提问人:Parth 提问时间:10/24/2023 最后编辑:Parth 更新时间:10/25/2023 访问量:65
如何在 Swift 内存中处理对 var 数组的更新(对 CoW 感到困惑)
How are updates to var arrays handled in Swift memory (confused about CoW)
问:
我有这个功能,可以在按降序对数字进行排序时进行快速选择分区。该函数是指在其范围之外定义的函数(分区是另一个函数中的嵌套函数)。arr
我的问题是,由于 Swift 中的数组是值类型,当我进行交换时,每次都会创建一个新副本吗?还是覆盖了相同的内存?
将函数定义为 更好,这样 arr 就可以通过引用传递?partition(start: Int, end: Int, arr: inout [(Int, Int)])
后续问题,当我们这样做时会发生什么?这会在内存中创建一个新副本吗?arr.append((4, 8))
func quickSelect(nums: [Int], k: Int) -> [Int] {
// ... some logic
var arr = [(Int, Int)]() // nums frequencies eg: [(1, 2), (3, 5), (2, 8)]
func partition(start: Int, end: Int) -> Int {
var swap = start
for i in start..<end {
if arr[i].1 > arr[end].1 {
(arr[i], arr[swap]) = (arr[swap], arr[i]) // arr copied on write?
swap += 1
}
}
(arr[end], arr[swap]) = (arr[swap], arr[end]) // arr copied on write?
return swap
}
// ... some logic
}
答:
不会在每次交换时都创建副本。
在这种情况下,您似乎误解了 copy-on-write 的含义。我们说 Swift 数组是写入时复制的,并不是因为每次我们写入它时都会创建一个副本。
Copy-on-write 的意思是“写入时复制”,而不是“每当结构被复制时复制”。您可能将其误解为“写入时复制”,而不是“写入时继续使用相同的存储”。如果它以这种方式工作,它就不会被称为“优化”:)
考虑数组的 where 和 are。的内容不会复制到 ,因为没有写入。 并共享相同的内部缓冲区,直到写入其中任何一个,此时将创建一个副本。var foo = bar
foo
bar
bar
foo
foo
bar
bar
foo
另请参阅以下文档:Array
数组,就像标准库中的所有可变大小集合一样, 使用写入时复制优化。阵列的多个副本共享 相同的存储,直到您修改其中一个副本。当这种情况发生时, 被修改的阵列将其存储替换为唯一拥有的 本身的副本,然后就地修改。优化包括 有时应用可以减少复制量。
这意味着,如果一个阵列与其他副本共享存储,则 该数组上的第一个突变操作会产生复制 数组。作为其存储的唯一所有者的阵列可以执行 更改操作到位。
如果像代码中一样,只有一个数组变量,则不需要副本。所有写入都可以写入同一阵列的内部缓冲区。数组的工作方式与任何其他结构体相同 - 其原理与分配结构体的属性 1000 次不会产生该结构体的 1000 个副本相同。
var s = SomeStruct()
for _ in 0..<1000 {
s.property = ... // this won't copy s 1000 times
}
如果在调用 之前先分配给另一个变量,则在第一次交换时将创建一个副本,之后不会再创建副本。arr
partition
至于调用 append
,数组可能需要增加其容量
来附加新元素。如果 ,则需要分配新内存。这可能涉及重新定位数组的内容,您可以将其视为“复制”:count == capacity
当数组需要在追加之前重新分配存储或其存储与另一个副本共享时,追加为 O(n),其中 n 是数组的长度。
评论
arr
partition
arr
inout
partition
arr
arr
partition
partition
arr
partition
partition
partition
评论