【问题标题】:Why storing substrings may lead to memory leak in Swift?为什么在 Swift 中存储子字符串可能会导致内存泄漏?
【发布时间】:2017-10-24 23:10:33
【问题描述】:

Substring 上的 Apple 文档中说:

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

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

【问题讨论】:

  • String 将其内容间接存储在(通常)引用计数缓冲区中。作为一个值类型并不能阻止它持有引用。

标签: swift string memory-leaks substring swift4


【解决方案1】:

Swift 数组、集合、字典和字符串具有值语义,但它们实际上是引用类型的写时复制包装器。换句话说,它们都是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

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

【讨论】:

  • 谢谢zneak。你的解释太棒了。
【解决方案2】:

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

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

HTH

【讨论】:

    猜你喜欢
    • 2017-05-09
    • 2011-06-12
    • 2013-07-12
    • 1970-01-01
    • 2017-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多