Swift如何解决DataCache缓存类引发的内存泄漏问题
内存泄漏问题原因及解决方案
根本原因
- 静态集合强持有:
Item类中的static var selection = [Item]()是和进程生命周期绑定的静态属性,你在duplicate方法中往该数组添加了100个Item实例,只要不主动清空数组,这些实例会被永久强持有,不会释放。 - 自动释放池未及时清理:主线程中创建的临时
Data实例会被自动加入当前线程的自动释放池,默认只有主线程RunLoop完成当前循环时才会清理池内对象。但你的main函数末尾是while (true) {}死循环,RunLoop永远无法完成当前循环,导致自动释放池中所有临时对象(包括大量大体积Data实例)持续驻留内存。而后台线程的GCD任务会被系统自动包裹自动释放池,任务执行完成后就会清理池内对象,所以后台创建的实例可以正常释放。 - 临时对象未及时回收:
DataCache的data是计算属性,本身不存储Data实例,内存中存在的Data都是读写时生成的临时实例,只要自动释放池未清理就会一直留存。
修复方案
1. 及时清理静态集合
用完selection数组后主动清空,切断强引用:
performOnSelection() { item in let _ = Item(item) } // 新增清空逻辑 Item.selection.removeAll()
如果没有全局留存的必要,建议不要用静态属性存储临时生成的对象。
2. 手动添加自动释放池
在创建大量临时对象的位置手动包裹autoreleasepool,强制临时对象及时释放:
- 包裹
Item初始化逻辑
init() { autoreleasepool { let tempData = Data(String(repeating: "dummy", count: 4_000_000).utf8) itemData = DataCache(id: id, data: tempData) } }
- 包裹循环创建实例的逻辑
func duplicate(times: Int) { for index in 0..<times { print(index) autoreleasepool { Item.selection.append(Item(self)) } } }
- 如果死循环是测试/常驻逻辑,每次循环也要包裹自动释放池
while (true) { autoreleasepool { sleep(1) } }
3. 优化DataCache设计
如果不需要在初始化时就写入数据,可以调整DataCache初始化方法,避免初始化时生成大体积临时Data,仅在需要读写时操作文件即可。
内容的提问来源于stack exchange,提问作者cire1776
相关产品推荐
相关产品推荐

