为什么存储子串可能会导致Swift内存泄漏?

时间:2017-10-24 23:10:34

标签: swift string memory-leaks substring swift4

关于Apple Substring的文档,请说:

  

不要将子字符串存储的时间超过执行特定操作所需的时间。子字符串包含对它来自的字符串的整个存储的引用,而不仅仅是对它所呈现的部分的引用,即使没有对原始字符串的其他引用也是如此。因此,存储子字符串可以延长不再可访问的字符串数据的生命周期,这可能看起来是内存泄漏。

我感到困惑的是,String是Swift中的值类型,它是如何导致内存泄漏的?

2 个答案:

答案 0 :(得分:1)

Swift Arrays,Sets,Dictionaries和Strings具有值语义,但它们实际上是用于引用类型的copy-on-write包装器。换句话说,它们是struct周围的所有class包装器。这允许以下工作而无需复制:

let foo = "ABCDEFG"
let bar = foo

当您写入String时,它使用标准库函数isUniquelyReferencedNonObjC(除非它再次重命名)以检查是否有多个对支持对象的引用。如果是这样,它会在修改之前创建一个副本。

var foo = "ABCDEFG"
var bar = foo // no copy (yet)
bar += "HIJK" // backing object copied to keep foo and bar independent

当您使用Substring(或数组切片)时,您将获得对整个支持对象的引用,而不仅仅是您想要的位。这意味着如果你有一个非常大的字符串并且你有一个只有4个字符的子字符串,只要子字符串是活的,你就可以将整个字符串后备缓冲区保存在内存中。这是这个警告你的泄漏。

答案 1 :(得分:0)

鉴于Swift经常被描绘的方式,你的困惑是可以理解的。 StringArrayDictionary等类型显示值语义,但是是由值和引用类型的组合构造的库类型。

这些类型的实现使用动态分配的存储。此存储可以在不同值之间共享。但是,库工具用于实现 copy-on-write ,以便根据需要复制此类共享存储以维护值语义,即类似于值类型的行为。

HTH