SwiftUI Realm内存问题:批量写入7000张图片时RAM占用持续升高
问题根因
- autoreleasepool位置错误:你当前的autoreleasepool仅包裹了向realmQueue提交异步任务的代码,队列内部执行的循环逻辑完全不在自动释放池的作用范围内,循环过程中生成的图片Data、ImageSaved对象等autorelease资源无法被及时释放,只会在整个异步任务执行完毕后才会统一回收。
- 网络请求方式不合理:
Data(contentsOf:)本质是用于读取本地文件的API,用于请求网络资源时会生成大量不可控的中间内存对象,且同步执行的特性会让所有临时资源都堆积在当前线程的内存中。 - Realm线程缓存未清理:Realm会默认在当前操作线程持有已访问对象的内存缓存,你没有主动清理的情况下,写入的大体积图片数据会被一直缓存,导致内存持续上涨。
- 批处理逻辑存在缺陷:计数变量x初始值为0,第一次触发
x%100 == 0时数组内仅存入了1张图片,和你预期的100张一批的逻辑不符,且循环结束后剩余不满100张的图片不会被写入数据库。 - 大体积数据直接存入Realm不合理:Realm官方明确建议超过16KB的二进制数据不要直接存在数据库中,会大幅提升读写操作的内存开销,更合理的方案是把图片存在沙盒,数据库仅存储本地文件路径。
修复后的代码示例
func downloadImages() { realmQueue.async { let realm = try! Realm() print("6.5: Downloading Images") var imageSavedArray : [ImageSaved] = [] let imageUrls = self.urlPrep() let batchSize = 100 for (index, url1) in imageUrls.enumerated() { // 每次循环都加autoreleasepool及时释放本次产生的临时对象 autoreleasepool { guard let imageURL = URL(string: url1) else { print("Invalid Saving Process for " + url1) return } guard let data = try? Data(contentsOf: imageURL) else { print("Download failed for " + url1) return } let imageToSave = ImageSaved() imageToSave.link = url1 imageToSave.data = data imageSavedArray.append(imageToSave) // 满100张执行批量写入 if imageSavedArray.count == batchSize { try! realm.write { realm.add(imageSavedArray) } imageSavedArray.removeAll() // 清理当前线程Realm缓存 realm.invalidate() } } } // 循环结束后写入剩余不满100张的图片 autoreleasepool { if !imageSavedArray.isEmpty { try! realm.write { realm.add(imageSavedArray) } imageSavedArray.removeAll() } realm.invalidate() } } }
额外优化建议
- 建议替换
Data(contentsOf:)为URLSession异步下载请求,可控制并发数、支持断点续传,也能更好的管控内存占用。 - 如果图片体积普遍偏大,务必修改存储逻辑:将图片写入沙盒的Library/Caches目录,Realm仅存储图片的本地路径和原始下载链接,可大幅降低数据库操作的内存压力和IO开销。
内容的提问来源于stack exchange,提问作者MoLoW
相关产品推荐
相关产品推荐

