【问题标题】:Swift 3 enums leak memory when the class contains an array当类包含数组时,Swift 3 枚举会泄漏内存
【发布时间】:2017-07-24 22:42:23
【问题描述】:

我在 Swift 中发现了内存泄漏。它让我做噩梦,因为我的代码到处都是小漏洞,然后我设法将其简化为这个小例子,

import UIKit

enum LeakingEnum {
    case
    LeakCase,
    AnotherLeakCase
}

class Primitive {
    var lightingType: LeakingEnum = .LeakCase
    var mysub : [Int] = []
    init() {
        mysub.append(80)
    }
}

class ViewController: UIViewController {
    var prim: Primitive?
    override func viewDidLoad() {
        super.viewDidLoad()
        prim = Primitive()
    }
}

如果您在 iPhone 上运行此程序并使用 Instruments 进行配置文件,您会在 Array._copyToNewBuffer 中发现此泄漏,

如果我删除对mysub.append 的调用,它将停止泄漏。如果我从Primitive 中删除枚举,它也会停止泄漏。我有这样的枚举泄漏的所有类。 Swift 枚举发生了什么?

在 iPhone6 和 iPad Pro 上的 Swift 3、Xcode 8.2.1 和 iOS 10.2 中重现。无法在模拟器或装有 iOS 9.3.2 的设备中重现。 你可以在这里下载一个最小的示例应用程序:https://github.com/endavid/SwiftLeaks

这是一个已知的错误吗?有什么解决办法吗?

编辑:

因为这让我想起了另一个枚举错误Accessor gives the wrong value in Swift 1.2/2.0 Release build only,所以我尝试将枚举设为@objc Int 枚举,但它仍然泄漏。但是,将lightingType 直接设为Int 确实可以修复泄漏...

编辑2: 将我的 iPhone 更新到 10.3 并将 Xcode 更新到 8.3 后,泄漏就消失了。好像是 iOS 10.2 的问题……

【问题讨论】:

  • 由于您在将其提炼成一个小示例方面做得非常出色,因此最好的方法是在 bugs.swift.org 上打开一个缺陷。
  • 令人费解。根据定义,泄漏是在对象不再使用后仍然存在的内存分配。我将 var Prim 移动到 viewDidLoad 函数中,并引用它以确保编译器没有删除它。没有泄漏!也许是仪器问题?
  • 这是一个 Swift 问题,还是与实现有关的问题?我没有 Linux 可以尝试其他实现...所以我向 Apple 报告了它(错误号 30856358)
  • 我创建了与 Cocoa (Mac) 应用程序相同的测试用例。它不会泄漏。此外,您的测试用例不会在模拟器下报告泄漏。所以绝对是苹果的问题。
  • 感谢您的检查。苹果回复说他们无法重现这个问题......我也试过模拟器,它没有泄漏......它确实在我的 10.2 的 iPhone 6 上泄漏,我今天更新到 10.2.1,它仍然泄漏.

标签: ios swift memory-leaks enums


【解决方案1】:

嘿@endavid 设法一致地复制了这个问题。我们花了很多时间试图弄清楚发生了什么,您的帖子很有帮助!

这里是示例代码库:https://github.com/Giphy/ios-memory-leak-sample

雷达:https://openradar.appspot.com/radar?id=4992108083544064

我们正在开发 SDK,但出现了完全相同的问题,但略有不同。由于我们希望事物能够互操作,因此我们将 @objc 添加到枚举定义中,并且由于您的类有两个属性,一个枚举和一个可变数组,因此事情开始按照您描述的方式泄漏。

不断重现泄漏:

// Without @objc this enum won't leak
// however when this enum is included in a class
// which contains an array, it will leak
@objc enum leakingObjCMarkedEnum: Int {

    // Just some random cases.
    case apple, orange
}

// Wrapper class which contains an enum and Array
// The class needs to contain the the Array in order for
// the Enum to leak.
class WrapperClass {

  // Optional enums marked with @objc will leak.
  var leakyOptionalEnum: leakingObjCMarkedEnum?

  // Include an array to trigger this behaviour.
  // Empty arrays won't cause the leak, so lets add an arbitrary Int
  var myArray: [Int] = [80]
}

class ViewController: UIViewController {

  // Hang on to a reference to our Wrapper Class instance.
  var wc: WrapperClass?

  override func viewDidLoad() {
    super.viewDidLoad()

    // Allocate an instance of our class
    // and things will start leaking at this point.
    wc = WrapperClass()
  }
}

解决方法:

如果我们将可选的枚举类属性转换为非可选的,泄漏就会消失。

// Let's convert the optional property to a non-optional
var leakyOptionalEnum: leakingObjCMarkedEnum = .orange

编辑:

这是由@Apple 的家伙修复的: https://bugs.swift.org/browse/SR-5625 公关:https://github.com/apple/swift/pull/11341

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-22
  • 1970-01-01
  • 2017-11-25
  • 2016-07-04
  • 2020-03-19
  • 1970-01-01
相关资源
最近更新 更多