在 iOS 开发中,ANR(Application Not Responding)、OOM(Out Of Memory) 和 内存泄露(Memory Leak) 是常见的性能问题。以下是它们的定义、发生原因及预防措施:
1. ANR(Application Not Responding)
定义
ANR 是指应用程序在主线程上执行耗时操作,导致界面卡顿或无响应。
发生场景
-
主线程阻塞:
- 在主线程执行耗时操作(如网络请求、数据库查询、复杂计算)。
- 主线程被长时间占用,无法处理 UI 事件(如点击、滚动)。
-
死锁:
- 多个线程相互等待资源,导致主线程无法继续执行。
-
UI 更新延迟:
- 在主线程中频繁更新 UI 或执行大量布局计算。
示例代码
// 错误示例:在主线程执行耗时操作
DispatchQueue.main.async {
for i in 0..<1000000 {
print(i) // 模拟耗时操作
}
}
预防措施
-
异步执行:
- 将耗时操作放到后台线程执行。
DispatchQueue.global().async { // 耗时操作 DispatchQueue.main.async { // 更新 UI } } -
优化性能:
- 减少主线程的负担,避免频繁更新 UI。
-
避免死锁:
- 合理使用锁机制,避免线程相互等待。
2. OOM(Out Of Memory)
定义
OOM 是指应用程序占用的内存超过系统限制,导致被系统强制终止。
发生场景
-
内存占用过高:
- 加载大量图片、视频等资源。
- 缓存未及时释放。
-
循环引用:
- 对象之间相互强引用,导致无法释放。
-
大对象未释放:
- 如未释放的
UIViewController、UIView等。
- 如未释放的
示例代码
// 错误示例:循环引用导致内存无法释放
class Person {
var dog: Dog?
deinit { print("Person deinit") }
}
class Dog {
var owner: Person?
deinit { print("Dog deinit") }
}
var person: Person? = Person()
var dog: Dog? = Dog()
person?.dog = dog
dog?.owner = person
person = nil
dog = nil // Person 和 Dog 都不会被释放
预防措施
-
优化内存使用:
- 使用
UIImage的downsampling技术加载大图。 - 及时释放不再使用的资源。
- 使用
-
避免循环引用:
- 使用
weak或unowned打破循环引用。
class Dog { weak var owner: Person? // 使用 weak 打破循环引用 } - 使用
-
监控内存:
- 使用 Xcode 的 Memory Graph Debugger 检查内存泄露。
- 使用
Instruments的 Allocations 工具分析内存使用情况。
3. 内存泄露(Memory Leak)
定义
内存泄露是指应用程序中分配的内存未被释放,导致内存占用持续增加。
发生场景
-
循环引用:
- 对象之间相互强引用,导致无法释放。
-
未释放的闭包:
- 闭包捕获了外部变量,导致对象无法释放。
-
未释放的单例:
- 单例对象持有大量资源,未及时释放。
-
未移除的观察者:
- 使用
NotificationCenter或KVO后未移除观察者。
- 使用
示例代码
// 错误示例:闭包捕获 self 导致内存泄露
class ViewController: UIViewController {
var closure: (() -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
closure = {
self.doSomething() // 闭包捕获 self,导致内存泄露
}
}
func doSomething() {
print("Do something")
}
deinit {
print("ViewController deinit")
}
}
预防措施
-
避免循环引用:
- 使用
weak或unowned捕获self。
closure = { [weak self] in self?.doSomething() } - 使用
-
及时释放资源:
- 在
deinit中释放资源。
deinit { NotificationCenter.default.removeObserver(self) } - 在
-
使用工具检测:
- 使用 Xcode 的 Memory Graph Debugger 检查内存泄露。
- 使用
Instruments的 Leaks 工具分析内存泄露。
总结
| 问题 | 发生场景 | 预防措施 |
|---|---|---|
| ANR | 主线程执行耗时操作、死锁、UI 更新延迟 | 异步执行、优化性能、避免死锁 |
| OOM | 内存占用过高、循环引用、大对象未释放 | 优化内存使用、避免循环引用、监控内存 |
| 内存泄露 | 循环引用、未释放的闭包、未释放的单例、未移除的观察者 | 避免循环引用、及时释放资源、使用工具检测 |
通过合理的设计和优化,可以有效避免 ANR、OOM 和内存泄露问题,提升应用的性能和稳定性。