PDFKit生成多图片PDF内存不释放致崩溃求优化方案
解决PDFKit生成PDF时内存无法释放的问题
问题根源
- 递归调用会导致每一层函数上下文堆积在栈中,加上
PDFDocument一直持有所有生成的PDFPage,内存会持续飙升直到崩溃。 - 当前的
autoreleasepool只包裹了部分逻辑,没有覆盖单张图片转PDFPage的完整生命周期,没法及时释放临时对象的内存。 - 直接用
UIImage生成PDFPage,高清大图会一次性占用大量内存,未做针对性内存优化。
修复方案
- 替换递归为迭代循环:避免栈内存堆积,同时更灵活控制每一步的内存释放。
- 给单张图片处理单独加
autoreleasepool:确保每张图片转完PDFPage后,临时对象立即被释放。 - 写完PDF后立即销毁
PDFDocument:让系统及时回收所有页面占用的内存。 - 优化图片内存占用:将
UIImage转成CGImage,或对大图进行压缩后再处理。
修改后的代码示例
func createPdf(from imageData: [UIImage], name: String) { let pdfDocument = PDFDocument() let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] var outputURL = documentDirectory.appendingPathComponent("PDFReader") // 先创建存储目录 do { try FileManager.default.createDirectory(at: outputURL, withIntermediateDirectories: true) outputURL = outputURL.appendingPathComponent("\(name).pdf") } catch { print(error.localizedDescription) return } // 迭代处理每张图片,每张单独用autoreleasepool包裹 for (index, image) in imageData.enumerated() { autoreleasepool { // 转CGImage减少内存占用,避免UIImage的额外解码开销 guard let cgImage = image.cgImage else { return } let pdfPage = PDFPage(image: UIImage(cgImage: cgImage))! pdfDocument.insert(pdfPage, at: index) } } // 写入PDF操作单独加autoreleasepool autoreleasepool { do { try pdfDocument.write(to: outputURL) print("Write Successfully") } catch { print(error.localizedDescription) } } // 手动清空页面并置空,让PDFDocument立即被系统回收 pdfDocument.removeAllPages() }
额外优化建议
- 如果图片是从本地文件读取的,尽量直接用
Data或CGImageSource加载,避免UIImage自动解码带来的额外内存占用。 - 对超大尺寸图片,可以先按PDF标准页面尺寸(如A4)等比例缩放,减少单页PDF的内存消耗。
内容的提问来源于stack exchange,提问作者Muhammad Bilal Raza
相关产品推荐
相关产品推荐

