测量强/弱ARC引用影响 - 对执行时间的影响

时间:2017-04-12 18:58:58

标签: ios swift performance automatic-ref-counting

我想知道强(弱)引用管理是否(以及多少)对代码执行有影响,特别是在释放许多类可能具有弱引用的对象时。起初我把它误认为是ARC,但事实并非如此。

在同一主题上有类似的question,但是他们不会调查性能影响或尝试从中提取数字。

让我说清楚一点:我不以任何方式暗示ARC或强弱/弱势可能会对表现产生不良影响,或者说不会使用这个" 。我喜欢这个。我只是好奇它的效率,以及如何调整它的大小。

我已将这段代码放在一起,以了解强/弱引用对执行时间的性能影响。

import Foundation

class Experiment1Class {
    weak var aClass: Experiment1Class?
}

class Experiment2Class {
    var aClass: Experiment2Class?
}

var persistentClass: Experiment1Class? = Experiment1Class()
var nonWeakPersistentClass: Experiment2Class? = Experiment2Class()

var classHolder = [Experiment1Class]()
var nonWeakClassholder = [Experiment2Class]()

for _ in 1...1000 {
    let aNewClass = Experiment1Class()
    aNewClass.aClass = persistentClass
    classHolder.append(aNewClass)

    let someNewClass = Experiment2Class()
    someNewClass.aClass = nonWeakPersistentClass
    nonWeakClassholder.append(someNewClass)
}

let date = Date()
persistentClass = nil
let date2 = Date()

let someDate = Date()
nonWeakPersistentClass = nil
let someDate2 = Date()

let timeExperiment1 = date2.timeIntervalSince(date)
let timeExperiment2 = someDate2.timeIntervalSince(someDate)

print("Time: \(timeExperiment1)")
print("Time: \(timeExperiment2)")

这段代码只测量释放对象和设置为nil所有引用所花费的时间。

如果你在Playground(Xcode 8.3.1)中执行它,你会看到10:1的比例,但Playground执行比实际执行慢得多,所以我还建议用" Release&#执行上面的代码34;构建配置。

如果您在Release I中执行,建议您将迭代计数设置为" 1000000"至少,我这样做的方式:

  • 将上述代码插入文件test.swift
  • 来自终端,运行swiftc test.swift
  • 执行./test

通过这种测试,我相信绝对的结果毫无意义,我相信这对99%的常用应用都没有影响......

到目前为止,我的结果显示,在Mac上执行的Release配置:

Time: 3.99351119995117e-06
Time: 0.0

然而,在我的iPhone 7Plus中,在Release中执行相同的操作:

Time: 1.4960765838623e-05
Time: 1.01327896118164e-06

显然,此测试显示对典型应用程序的实际影响几乎没有任何顾虑。

以下是我的问题:

  • 您能想出任何其他方法来衡量强/弱引用对执行时间的影响吗? (我想知道该系统采取了哪些策略来改进这一点)
  • 其他哪些指标可能很重要? (如多线程优化或线程锁定)
  • 我该如何改进?
  

编辑1

我发现这个LinkedList测试非常有趣,原因如下:请考虑以下代码:

//: Playground - noun: a place where people can play
import Foundation
var n = 0
class LinkedList: CustomStringConvertible {
    var count = n
    weak var previous: LinkedList?
    var next: LinkedList?
    deinit {
        // print("Muorte \(count)")
    }
    init() {
        // print("Crea \(count)")
        n += 1
    }
    var description: String {
        get {
            return "Node \(count)"
        }
    }

    func recurseDesc() -> String {
        return(description + " > " + (next?.recurseDesc() ?? "FIN"))
    }
}

func test() {
    var controlArray = [LinkedList]()
    var measureArray = [LinkedList]()

    var currentNode: LinkedList? = LinkedList()

    controlArray.append(currentNode!)
    measureArray.append(currentNode!)

    var startingNode = currentNode

    for _ in 1...31000 {
        let newNode = LinkedList()
        currentNode?.next = newNode
        newNode.previous = currentNode!
        currentNode = newNode

        controlArray.append(newNode)
        measureArray.append(newNode)
    }
    controlArray.removeAll()
    measureArray.removeAll()

    print("test!")
    let date = Date()
    currentNode = nil
    let date2 = Date()

    let someDate = Date()
    startingNode = nil
    let someDate2 = Date()

    let timeExperiment1 = date2.timeIntervalSince(date)
    let timeExperiment2 = someDate2.timeIntervalSince(someDate)

    print("Time: \(timeExperiment1)")
    print("Time: \(timeExperiment2)")
}

test()

我发现以下内容(在发布配置中运行):

  • 我无法在手机上运行超过32000次迭代,它在退出期间崩溃了EXC_BAD_ACCESS(是的,在DEINIT期间......这不奇怪)
  • ~32000次迭代的时间是0对0.06秒,这是巨大的!

我认为这个测试非常占用CPU,因为节点是一个接一个地释放的(如果你看到代码,只有下一个是强大的,前一个很弱)...所以一旦第一个被释放,其他人一个接一个地落下,但并非完全落下。

1 个答案:

答案 0 :(得分:1)

实际上没有自动内存管理这样的东西。无论您是否使用ARC,内存都由retainrelease管理。不同之处在于谁编写代码,您或编译器。有写的手动内存管理代码,还有ARC写的手动内存管理代码。理论上,如果您正确地执行了此操作,ARC会在您的代码中完全插入相同的retainrelease命令。因此,性能上的差异应该是微不足道的。