Swift uses automatic reference counting (ARC) to manage the memory usage of the application. In most cases, it is not necessary to consider the management of memory. When an instance is no longer needed, ARC automatically frees the memory used by these instances.
But arc is not absolutely safe. There are two scenarios in which a memory leak occurs.
1, cyclic strong references between class instancesTwo class instances have a strong reference to each other, which is a case of a strong reference loop, which results in a memory leak.
1234567891011121314151617181920212223242526272829303132333435363738394041 |
class Teacher {
var tName :
String
var student :
Student
?
init
(name:
String
){
tName = name
println
(
"老师\(tName)实例初始化完成"
)
}
deinit{
println
(
"老师\(tName)实例反初始化完成"
)
}
}
class Student {
var sName :
String
var teacher :
Teacher
?
init
(name:
String
){
sName = name
println
(
"学生\(sName)实例初始化完成"
)
}
deinit{
println
(
"学生\(sName)实例反初始化完成"
)
}
}
//测试开始
var teacher:
Teacher
?
var student:
Student
?
teacher =
Teacher
(name:
"李老师"
)
student =
Student
(name:
"刘同学"
)
teacher!.student = student
student!.teacher = teacher
teacher =
nil
student =
nil
//测试结果(deinit未调用,则内存泄露)
老师李老师实例初始化完成
学生刘同学实例初始化完成
|
WORKAROUND: Use weak references
Just add the student variable of the example teacher class to the keyword weak, or add the teacher variable of the student class to the keyword weak.
When a class contains an instance of a weakly referenced class B, and a strong reference instance exists in Class B, if A is released, the release of B is not affected. However, A's memory collection waits until the instance of B is released before it can be reclaimed.
123456789101112131415161718192021222324252627 |
class Teacher {
var tName :
String
weak var student :
Student
?
init
(name:
String
){
tName = name
println
(
"老师\(tName)实例初始化完成"
)
}
deinit{
println
(
"老师\(tName)实例反初始化完成"
)
}
}
class Student {
var sName :
String
var teacher :
Teacher
?
init
(name:
String
){
sName = name
println
(
"学生\(sName)实例初始化完成"
)
}
deinit{
println
(
"学生\(sName)实例反初始化完成"
)
}
}
|
2, cyclic strong references due to closures
A strong reference loop occurs when a closure is assigned to a property of a class instance, and an instance is used in the closure body.
12345678910111213141516171819202122232425262728293031 |
class JsonElement
{
let name:
String
let jValue:
String
?
lazy var asJson:() ->
String = {
if let text =
self
.jValue {
return "\(self.name):\(text)"
}
else
{
return "text is nil"
}
}
init
(name:
String
, text:
String
){
self
.name = name
self
.jValue = text
println
(
"初始化闭包"
)
}
deinit{
println
(
"闭包释放"
)
}
}
//开始测试
var p:
JsonElement
? =
JsonElement
(name:
"p"
, text:
"hangge.com"
)
println
(p!.asJson())
p =
nil
//测试结果(deinit未调用,则内存泄露)
初始化闭包
p:hangge.com
|
Workaround: Use a closed-packet capture list
When the closure and the instance always refer to each other and release simultaneously, the definition of the closure capture list is no master reference. However, when the capture reference may be nil, the definition of the capture list is a weak reference. A weak reference is typically an optional type, and is set to nil after the instance is disposed.
1234567891011121314151617181920212223 |
class JsonElement
{
let name:
String
let jValue:
String
?
lazy var asJson:() ->
String = {
[
unowned self
]
in //使用无主引用来解决强引用循环
if let text =
self
.jValue {
return "\(self.name):\(text)"
}
else
{
return "text is nil"
}
}
init
(name:
String
, text:
String
){
self
.name = name
self
.jValue = text
println
(
"初始化闭包"
)
}
deinit{
println
(
"闭包释放"
)
}
}
|
Swift-memory leak reason (cyclic strong reference) and solutions