【问题标题】:Swift saving multiple images to the filesystem at once, High CPU一次将多个图像快速保存到文件系统,高 CPU
【发布时间】:2019-05-01 07:35:45
【问题描述】:

我有以下功能,我需要清除数据库中的所有图片列并移动到文件系统。当我一口气完成所有这些时,内存太多,它会崩溃。我切换到递归函数并进行了 20 次的写入和批处理。

我需要为大约 6 张桌子执行此操作。我的 Realm DB 中有 2 个半演出数据。在我调用我的 6 个递归函数、取出图像并压缩 Realm 后,它会切换到 40mb。

我可以看到非常高的内存使用率,因为我的函数被调用并且内存较少的手机将无法处理它。

如何在每个函数之间释放内存和 CPU?

public static func clearEqCatPics(){

        let docsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        let eqcatPicDir = docsDir.appendingPathComponent(util_Constants.DIR_EQCAT_PICS)

        do {
            var realm : Realm? = try Realm()
            let predicate = NSPredicate(format: "icon != %@", "")
            let categories = realm!.objects(STD_EQ_category.self).filter(predicate).sorted( by: [SortDescriptor(keyPath: "displayorder", ascending: true), SortDescriptor(keyPath: "_id", ascending: true)] )

            if (categories.count > 0)
            {
                realm?.beginWrite()
                let upper = categories.count > 20 ? 20 : categories.count

                var actualCounter = upper
                for i in 0..<upper{
                    autoreleasepool{
                        if let proPicData = Data(base64Encoded: categories[actualCounter - 1].icon, options: .ignoreUnknownCharacters) {


                            let filename = eqcatPicDir.appendingPathComponent(categories[actualCounter - 1]._id.description+".jpg")

                            (proPicData as NSData).writeToURL2(named: filename, completion: { (result, url) -> Void in

                            })

                            categories[actualCounter - 1].icon = ""

                        }
                        else{
                            categories[actualCounter - 1].icon = ""
                        }
                    }

                    actualCounter = actualCounter - 1

                }

                try realm?.commitWrite()
                let eqcatNew = realm!.objects(STD_EQ_category.self).filter(predicate)
                print("$$$$$$$$$$$$$$$$$$$$ 2. eqcatNew COUNT : \(eqcatNew.count) $$$$$$$$$$$$$$$$$$$$")
                realm = nil
                if eqcatNew.count > 0 {
                    clearEqCatPics()
                }
            }
            realm = nil
        }
        catch let error as NSError {
            print("error realm \(error.localizedDescription)")

        }

    }

writeToURL2 在哪里:

我需要摆脱扩展程序中的弱自我,因为我正在通过多个项目的守卫让并且正在跳过负载

extension NSData {

    func writeToURL2(named:URL, completion: @escaping (_ result: Bool, _ url:NSURL?) -> Void)  {


        let tmpURL = named as NSURL

        //[weak self]
        DispatchQueue.global(qos: .background).async {  () -> Void in

            //guard let strongSelf = self else { print("self was weak"); completion (false, tmpURL); return }

            self.write(to: tmpURL as URL, atomically: true)
            var error:NSError?
            if tmpURL.checkResourceIsReachableAndReturnError(&error) {
                print("We have it")
                completion(true, tmpURL)
            } else {
                print("We Don't have it\(error?.localizedDescription)")
                completion (false, tmpURL)
            }

        }

    }
}

编辑

我将 for 循环中的 writeToURL 更改为以下内容:

do {
     try proPicData.write(to: filename, options: [.atomic])                               
}
catch let err as NSError{
     print("err : \(err.localizedDescription)")
}

它有助于记忆,但有时我得到 Thread1: EXC_BAD_ACCESS 指向行 try proPicData.write...

仍然有很高的 CPU 使用率。是否有清除每个函数调用之间的 CPU 使用率?

【问题讨论】:

    标签: swift recursion memory uiimage realm


    【解决方案1】:

    您正在同时获取 Realm 中的所有对象,这就是占用这么多内存的原因

    let categories = realm!.objects(STD_EQ_category.self).filter(predicate).sorted( by: [SortDescriptor(keyPath: "displayorder", ascending: true), SortDescriptor(keyPath: "_id", ascending: true)] )

    写入文件并不是占用内存的原因,尽管这可能与 CPU 使用率有关。

    我建议在类别提取上放置一个limit,这样您就不会将所有类别及其图像加载到内存中。否则,请尝试提出一个 fetch 谓词,否则会以合理的方式限制数据。

    【讨论】:

    • 只有当我通过并访问我的 for 循环中的领域对象时,它们才会加载到内存中。因为它们是懒加载的。我将写入更改为 url,现在我没有将其推迟到后台线程,而是直接在我的 for 循环中调用普通 data.write(to url, option: [.atomic], 现在内存达到 50 或60mb 但 CPU 升得太高导致崩溃
    • 您是否尝试过使用仪器来准确查看问题所在?否则,realm.commitWrite() 一次做太多工作试图释放图像可能有问题?
    • 在仪器中进行分析时,我究竟在哪里看到这个?
    • 我在 Time Profiler 上获得了最好的运气 - 尝试使用它。您可能需要稍微摆弄一下(也许是您的代码)才能获得高质量的输出。您也可以尝试其他实用程序,几乎可以从列表中选择一个听起来可以帮助您的工具。
    猜你喜欢
    • 1970-01-01
    • 2012-06-12
    • 1970-01-01
    • 1970-01-01
    • 2019-08-30
    • 2021-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多