当类包含数组时,Swift 3枚举泄漏内存 [英] Swift 3 enums leak memory when the class contains an array

查看:272
本文介绍了当类包含数组时,Swift 3枚举泄漏内存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Swift发现内存泄漏。它给了我恶梦,因为我的代码遍布各处的小泄漏,然后我设法将其减少到这个小例子,

  import UIKit 

枚举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()
}
}
/ pre>

如果您在iPhone和配置文件上运行此程序,您将在 Array._copyToNewBuffer





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



转载于Swift 3,Xcode 8.2.1和iOS 10.2,在iPhone6和iPad Pro上。无法在模拟器或iOS 9.3.2设备中复制。
您可以在这里下载最小的示例应用程序: https://github.com/endavid/SwiftLeaks



这是一个已知的错误吗?有没有工作?



编辑:



因为这提醒我另一个枚举错误,访问者在Swift 1.2 / 2.0版本版本中给出错误的值,我尝试使枚举为code> @objc Int 枚举,但它仍然泄漏。但是,直接将 lightingType 直接 Int 可以修复泄漏...



编辑2:
将iPhone更新为10.3,将Xcode更新为8.3后,泄漏就消失了。这似乎是iOS 10.2的一个问题...

解决方案

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



这是示例repo: https://github.com/Giphy/ios-memory-leak-sample



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



我们开发的SDK和相同的确切问题浮出水面,差别很小。因为我们想要交互的东西,我们在枚举定义中添加了 @objc ,事情开始泄漏,正如你所描述的那样,你的类有两个属性,一个枚举和一个可变数组



一致地转载泄漏:



  //没有@objc这个枚举不会泄漏
//但是当这个枚举包含在一个包含数组的类
//中时,它会泄漏
@objc enum leakingObjCMarkedEnum:Int {

//只是一些随机的情况。
case apple,orange
}

//包含枚举和数组的包装类
//该类需要包含该数组,以便
//枚举泄漏。
class WrapperClass {

//用@objc标记的可选枚举将泄漏。
var leakyOptionalEnum:leakingObjCMarkedEnum?

//包含数组来触发此行为。
//空数组不会导致泄漏,所以可以添加任意的Int
var myArray:[Int] = [80]
}

class ViewController :UIViewController {

//挂起对我们的Wrapper类实例的引用。
var wc:WrapperClass?

覆盖func viewDidLoad(){
super.viewDidLoad()

//分配我们的类
//的一个实例,事情会开始泄漏在此刻。
wc = WrapperClass()
}
}





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

  //我们将可选属性转换为非可选的
var leakyOptionalEnum:leakingObjCMarkedEnum = .orange



编辑:



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


I found a memory leak in Swift. It gave me nightmares because my code was full of small leaks everywhere, and then I managed to reduce it to this small example,

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()
    }
}

If you run this program on an iPhone and Profile with Instruments, you'll find this leak in Array._copyToNewBuffer,

If I remove the call to mysub.append, it stops leaking. If I remove the enum from Primitive, it stops leaking as well. All the classes where I have an enum leak like this. What's going on with Swift enums?

Reproduced in Swift 3, Xcode 8.2.1, and iOS 10.2, on both an iPhone6 and an iPad Pro. Can't reproduce in the Simulator, or in a device with iOS 9.3.2. You can download a minimal sample app here: https://github.com/endavid/SwiftLeaks

Is this a known bug? Is there any work around?

Edit:

Because this remind me of another enum bug, Accessor gives the wrong value in Swift 1.2/2.0 Release build only, I tried making the enum an @objc Int enum, but it still leaks. However, making lightingType directly an Int does fix the leak...

Edit2: After updating my iPhone to 10.3 and Xcode to 8.3, the leak is gone. It seems it was an issue of iOS 10.2...

解决方案

Hey @endavid managed to replicate the issue consistently. We spend a good time trying to figure out what was going on and your post helped a lot!

Here is the sample repo: https://github.com/Giphy/ios-memory-leak-sample

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

We are developing SDKs and same exact issue surfaced with a small difference. Since we wanted things to interop we added @objc to the enum definition and things started to leak exactly the way you described given your class has two properties, one enum and one mutable array.

Consistently reproduced the leak:

// 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()
  }
}

Work Around:

If we convert the optional enum class property to a non-optional, leak will disappear.

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

Edit:

It is fixed by guys @ Apple: https://bugs.swift.org/browse/SR-5625 PR: https://github.com/apple/swift/pull/11341

这篇关于当类包含数组时,Swift 3枚举泄漏内存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆