What does "outlined destroy" mean?
I’m not 100% sure what’s going on here but I can explain some of this. To start, let’s consider frame 1 of your backtrace:
1 ReSchedule … outlined destroy of Event + 544 (<compiler-generated>:0)
<compiler-generated>:0
means pretty much what you’d expect. This code has been generated by the compiler, and hence there’s no meaningful line number, and hence you see a line number of 0.
Next, consider
outlined destroy of Event
.
Event
is obviously the name of your type. In this context,
outlined means the opposite of
inlined. To understand this, you have to understand a little bit about how Swift structures interact with Swift classes.
Imagine you have a Swift structure like this:
struct Event {
var obj: Obj
}
where
Obj
is some class type. This structure must hold a reference to
Obj
to guarantee that it doesn’t get deallocated. Now consider what happens when you make a copy of the structure:
var e1: Event = … something …
if true {
var e2 = e1
e1.obj = Obj(name: "obj3")
e2.obj = Obj(name: "obj4")
}
When you do the copy,
e2
must separately retain the object because, after you’ve done the copy, you can modify
e1.obj
and
e2.obj
independently. Consequently, when
e2
goes out of scope (on line 6 in this example), it must release the reference to
e2.obj
.
The Swift runtime knows about all the object references within a structure and takes care of all of these retains and releases for you (in fact, many of them are optimised away by the compiler). In simple cases the code to do these retains and releases is inlined directly into your code. In more complex cases, this code is outlined into a separate routine. That is, the compiler synthesises a routine to do the retains and releases and then calls that routine.
Note What is the definition of complex here? I don’t know for sure, but in my tests, using Xcode 10.2.1 with optimisations turned off, I started seeing outlined routines as soon as
Event
had more than one object reference.
To continue the above example, if the
Event
structure contains lots of object references, inlining all of these retains and releases into every routine that used that structure would result in massive code bloat. Instead, the compiler generates routines like
outlined retain of Event
and
outlined release of Event
to do that work.
In your case you are crashing in one of those routines,
outlined destroy of Event
. The compiler is cleaning up an
Event
structure, that structure is too complex to have the cleanup code inlined, and thus the compiler has generated an outlined routine and has called that. It’s this routine that’s crashed, presumably because one of the object references in the structure is invalid.
For example, consider the test code pasted in at the end of this post, which has a deliberate memory management error. When I put that code into a command-line tool, it crashes on line 24 with a backtrace like this;
0 … __pthread_kill + 10
1 … pthread_kill + 284
2 … abort + 127
3 … malloc_vreport + 545
4 … malloc_report + 151
5 … Obj.__deallocating_deinit + 47
6 … _swift_release_dealloc + 16
7 … outlined destroy of Event + 16
8 … main() + 14 (main.swift:32)
9 … main + 20 (main.swift:34)
10 … start + 1
As you can see frame 7 matches frame 1 of the backtrace in your crash report.
So, where does this leave you? It seems that you have some sort of memory management error associated with the properties of your
Event
structure. It’s hard to say what that is. You could potentially work it out by disassembling the
outlined destroy of Event
routine to work out what property is being deallocated at offset 544. However, that would be tricky.
My recommendation right now is that you run your app under the standard memory debugging tools to see if they give you any hints as to what’s going wrong.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"
class Obj {
init(name: String) {
self.name = name
}
var name: String
}
struct Event {
var obj: Obj
var obj2: Obj
}
struct Test {
func test() {
print(">test")
var e1: Event = Event(obj: Obj(name: "obj1"), obj2: Obj(name: "obj2"))
if true {
var e2 = e1
e1.obj = Obj(name: "obj3")
e2.obj = Obj(name: "obj4")
let u = Unmanaged.passUnretained(e2.obj)
u.release()
}
print("<test")
}
}
func main() {
let t = Test()
t.test()
}
main()