【问题标题】:Swift - iterating through characters in string causes memory leakSwift - 遍历字符串中的字符会导致内存泄漏
【发布时间】:2017-05-09 22:53:13
【问题描述】:

这是我的第一篇文章!我对 Swift 比较陌生,并且没有计算机科学背景,所以我仍然容易遇到很多新手问题 - 但到目前为止我已经能够解决所有问题,部分原因是浏览了优秀的答案在 StackOverflow 上。但是,我遇到了一些让我非常困惑的事情,我花了整整一周的时间试图解决它,但没有成功。

我要做的是从 UITextView 中获取中文文本,然后将其转换为单个汉字数组,然后用于各种处理和分析。但是,这会导致泄漏。

在这个非常简化的示例中,它重现了相同的泄漏,有一个 TextView 和一个 Button;当用户按下按钮时,函数 makeArray 被调用,它将文本转换为一个字符数组(实际上是单个字符的字符串,因为我需要它是我将用它做的一些事情的字符串)。包含此函数的类 TextProcessing 用作单例(是的,我知道显然单例应该是坏的,原因我不完全理解,但由于涉及代码其他部分的各种原因,它在那里工作得最好是此类的单个实例),来自 UITextView 的文本被传递到其中,然后在其中转换为数组,如下所示:

class ViewController: UIViewController {
    @IBOutlet weak var textBox: UITextView!
    @IBOutlet weak var doneButton: UIButton!

    @IBAction func pressDoneButton(_ sender: Any) {
        let textToAnalyze = textBox.text!
        TextProcessing.textProcessing.makeArray(textToAnalyze)
    }
}

class TextProcessing {
    static let textProcessing = TextProcessing()

    private let language = "Chinese"
    private var sourceTextArray: [String]!

    func makeArray (_ sourceText: String) {
        if language == "Chinese" {
            sourceTextArray = sourceText.characters.map { String($0) }
        } else if language == "English" {
            sourceTextArray = sourceText.components(separatedBy: " ")
        }
        // then do some stuff with this array
    }
}

当我在 Leaks Instruments 上运行它时,我得到“Malloc 16 Bytes”和“CFString”的泄漏,每个实例的数量与数组元素的数量大致相同(因此细绳)。当我查看调用树并向下钻取时,问题行是“sourceTextArray = sourceText.characters.map { String($0) }”。

顺便说一句,相对较长的文本会发生这种情况 - 对于较短的文本,要么没有问题,要么 Instruments 没有检测到它。

但是,如果我通过根据空格将字符串分隔成单词来创建一个数组,就像我希望使用英语这样的语言一样,那么就没有泄漏 - 所以如果我在示例代码中将语言变量更改为“英语”,它工作正常(但当然不会给我我想要的数组)。我认为问题可能出在“map”方法中,因为它使用了闭包并且很容易出现闭包泄漏,但是当我尝试将其放入字符数组中的其他方法时,例如使用 for 循环和以这种方式遍历每个字符,它仍然有同样的问题。

如果不是从 UITextView 获取文本,而是这样做:

class ViewController: UIViewController {
    @IBOutlet weak var textBox: UITextView!
    @IBOutlet weak var doneButton: UIButton!

    @IBAction func pressDoneButton(_ sender: Any) {
        let textToAnalyze = "blah blah put a long string of Chinese text here"
        TextProcessing.textProcessing.makeArray(textToAnalyze)
    }
}

没有问题。同样,如果在 makeArray 函数中,如果我忽略 sourceText 而是这样做:

func makeArray (_ sourceText: String) {
    if language == "Chinese" {
        let anotherText = "blah blah some text here"
        sourceTextArray = anotherText.characters.map { String($0) }
    }
    // then do some stuff with this array
}

也没有泄漏。因此,从文本框中获取字符串,将其传递给函数,然后将其放入字符数组的组合会导致泄漏。

我花了无数个小时在互联网上搜索并阅读有关 Swift 中 ARC 的所有内容,并且我尝试了各种带有弱/无主等的东西,但似乎没有任何效果。这是怎么回事?如何解决?

编辑:

看来这可能只是模拟器和/或仪器的问题。当我在设备上运行它,并且只在 xcode 调试中监控内存使用情况时,即使执行 100 次以上也没有增加,所以我想没关系......它仍然会在 Instruments 中显示泄漏似乎很奇怪。

【问题讨论】:

  • 它工作正常。我用很长的文本尝试了你的代码 - 大约一百万个汉字:) - 并且没有泄漏!
  • class TextProcessing { static let textProcessing = TextProcessing() }...我不知道这是否是问题所在,但您当然不需要将此类重新实例化为自身内部的类变量。对象开始!
  • @3li 这很奇怪......每次我尝试使用超过几个段落的内容时,它总是会泄漏。我正在使用 XCode 8.2.1 和 Swift 3。内存分配怎么样 - 即使它没有为您检测到泄漏,如果您反复按下完成按钮,总内存是否会继续增加?
  • @twiz_ 是的,在这个简化的示例中,它看起来很奇怪,而且完全没有必要这样做,但是在我的“真实”代码中,我必须在整个生命周期中将此类的实例用作单例由于它所做的其他事情,我只是尝试遵循krakendev.io/blog/the-right-way-to-write-a-singleton 中描述的单身人士的最佳实践,无论如何,即使我更改它并以“正常”方式进行操作,我仍然有相同的内存泄漏问题,所以这似乎不是问题。

标签: ios swift memory-leaks


【解决方案1】:

这是仪器错误(有很多问题)。你的代码没问题。

【讨论】:

  • 嗯,我不太确定。这当然可能只是泄漏工具中的一个错误,但是当我在分配中运行它时,当我反复按下按钮时,总内存稳步增加。即使我根本不在仪器中运行它,只是在模拟器中,当我反复按下按钮时,总内存不断增加......所以很明显有些东西没有按应有的方式工作。
  • 好的,所以经过更多测试,您似乎是对的。问题是我只是在模拟器上而不是在设备上测试它。当我在设备上测试它时,Leaks 仪器仍然显示相同的泄漏,并且 Allocations 仍然显示内存在稳步上升,但是当我在设备上运行它并在 xcode 调试统计信息中查看内存时,并没有增加在记忆中,即使我做了 100 多次。 (在模拟器中,即使在 xcode 中,它也显示每次内存都在增加)所以,我猜这个组合(xcode + 设备)是最准确的,因此没问题???奇怪..
  • 是的,这很奇怪。但是 Instruments 是一个沉重的工具,很难写出没有 bug 的东西。 Xcode 也包含很多问题 :)
【解决方案2】:

我刚刚提交了一份错误报告 (FB7684067)。

以下简单的 macOS 命令行应用程序将在几分钟内增长到 1GB 以上:

import Foundation
let line = "124;5678;90123"
while true {
    let fields = line.components(separatedBy: ";")
    assert(fields[1] == "5678")
}

【讨论】:

  • 他们的回复是什么?我正在尝试追踪为什么按字符集分隔的组件会泄漏到自动释放池中,我很困惑。
猜你喜欢
  • 2011-06-12
  • 1970-01-01
  • 1970-01-01
  • 2011-11-09
  • 1970-01-01
  • 2021-05-01
  • 2012-06-15
  • 1970-01-01
  • 2014-04-30
相关资源
最近更新 更多