协议对保留计数有影响吗? [英] Do protocols have an effect on the retain count?
问题描述
我有一个非常简单的代码.我有目的创建了一个与委托相关的记忆周期.尝试观察和学习如何使用Xcode的内存图.
I have a very simple code. I’m PURPOSELY creating a memory cycle with a delegate. Trying to observe and learn how to use Xcode's Memory Graph.
我不明白的是为什么在连接部分中,Xcode表示存在 3 个连接.应该只有2.
What I don’t get is why in the connections sections, Xcode says there are 3 connections. There should only be 2.
如果我创建一个带有闭包的内存循环,那么它将显示 2 个连接.
If I create a memory cycle with with closures, then it will show 2 connections.
我与委托一起泄漏的代码:
My code for leaking with delegate:
protocol SomeDelegate {
func didFinishSomething()
}
class Something {
var delegate: SomeDelegate?
}
class ViewController: UIViewController, SomeDelegate {
var x = Something()
override func viewDidLoad() {
super.viewDidLoad()
print("view did load")
x.delegate = self
}
func didFinishSomething() {
print("something was finished")
}
deinit {
print("dellocated!!!")
}
}
我将该视图推送到navigationController中,然后返回.
I push that view into a navigationController then go back.
2个委托对象的内存地址略有不同,只是一个+16
The 2 delegate objects have a slightly different memory addresses, it differs just by a +16
似乎与委托对象是协议有关.因为当我删除该协议时,它缩减为 2 :
It seems that it has something to do with delegate object being a protocol. Because when I removed the protocol, then it reduced down to 2:
class Something2 {
var delegate: ViewController?
}
class ViewController: UIViewController {
var x = Something2()
override func viewDidLoad() {
super.viewDidLoad()
print("view did load")
x.delegate = self
}
deinit {
print("dellocated!!!")
}
}
推荐答案
我很确定这只是Xcode引起的困惑.协议值不应导致超出正常强引用的任何额外保留,因为内存管理操作通过存在容器中存储的类型元数据转发到基础值.
I'm pretty sure that this is just Xcode getting confused. A protocol value shouldn't cause any extra retains over a normal strong reference, as memory management operations are forwarded to the underlying value through the type metadata stored within the existential container.
这是一个最小的示例,可以在Xcode的内存图调试器中重现相同的结果:
Here's a minimal example that reproduces the same result in Xcode's memory graph debugger:
protocol P {}
class C : P {
var d: D?
}
class D {
var p: P?
}
func foo() {
let c = C()
let d = D()
c.d = d
d.p = c
}
foo()
print("insert breakpoint V")
print("insert breakpoint ^")
如果在打印语句之间插入一个断点并查看内存图,则会看到3个连接.有趣的是,如果在分配d.p
之后分配c.d
,则会看到2个连接的正确结果.
If you insert a breakpoint between the print statements and look at the memory graph, you'll see 3 connections. Interestingly enough, if you assign c.d
after you assign d.p
, you'll see the correct result of 2 connections instead.
但是,如果我们在swift_retain
和swift_release
上设置符号断点以查看强大的保留/释放Swift ARC流量(同时打印出存储在%rdi
寄存器中的值,该值似乎是所使用的寄存器)在x86上传递参数):
However if we set symbolic breakpoints on swift_retain
and swift_release
in order to see the strong retain/release Swift ARC traffic (while printing out the value stored in the %rdi
register, which appears to be the register used to pass the argument on x86):
,然后在调用foo()
之后立即插入一个断点,我们可以看到,在这两种情况下,实例各自保留+2并释放-2(请记住,它们以+1保留的形式进入世界,因此保持已分配):
and then insert a breakpoint immediately after the call to foo()
, we can see that in both cases the instances each get +2 retained and -2 released (bearing in mind they enter the world as +1 retained, thus keeping them allocated):
swift_retain 1
rdi = 0x000000010070fcd0
swift_retain 2
rdi = 0x000000010070fcd0
swift_release 1
rdi = 0x0000000000000000
swift_release 2
rdi = 0x000000010070fcd0
swift_retain 3
rdi = 0x00000001007084e0
swift_retain 4
rdi = 0x00000001007084e0
swift_release 3
rdi = 0x00000001007084e0
swift_release 4
rdi = 0x000000010070fcd0
swift_release 5
rdi = 0x00000001007084e0
所以看起来Xcode出了问题,而不是Swift.
So it looks like Xcode is at fault here, not Swift.
这篇关于协议对保留计数有影响吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!