PDDocument的save方法在服务端保存大文件时出现java heap space内存溢出
PDFBox处理大PDF触发OOM问题原因分析
- JVM堆内存配置不合理:服务端物理内存大不代表JVM可用堆内存大,若服务启动时
-Xmx参数配置值低于本地开发环境,处理大PDF时很容易触堆内存上限。 - PDFBox版本缺陷:2.0.20及更早版本的
MemoryUsageSetting缓存策略存在bug,即使配置setupTempFileOnly(),处理带大尺寸内嵌图片、复杂字体、结构异常的PDF时,仍会强制将全量内容加载到堆内存中。 - 资源未正确释放:现有代码未使用自动资源管理逻辑,若保存过程中抛出异常,
doc.close()不会执行,残留的PDDocument对象会长期占用堆内存,多次处理大文件后内存累计占用超标触发OOM。 - 保存阶段无内存限制:
doc.save()操作默认会在堆中缓冲部分写入数据,大文件保存时该部分缓冲会额外占用大量堆内存。
解决方案
调整服务端JVM启动参数
根据待处理PDF的最大尺寸设置合理的堆内存上限,例如处理单文件最大为2G的PDF,可将堆内存上限设为4G及以上,启动参数参考:java -Xms2g -Xmx4g -jar 你的服务包名.jar
调整后可通过jinfo -flags <进程ID>确认配置生效。升级PDFBox到最新稳定版
建议升级到2.0.32及以上版本,该版本修复了大量内存泄漏、缓存策略失效的已知问题。优化代码逻辑,使用try-with-resources自动释放资源
优化后的代码示例如下:
File sourceFile = new File(filePath); File targetFile = new File(pdfPath); try (PDDocument doc = PDDocument.load(sourceFile, password, MemoryUsageSetting.setupTempFileOnly())) { if (null == doc) { return false; } doc.setAllSecurityToBeRemoved(true); doc.save(targetFile); return true; } catch (IOException e) { // 自行处理异常逻辑 e.printStackTrace(); return false; }
- 进一步调优内存控制策略
如果仍出现OOM,可改用混合缓存模式,设置堆内存缓存阈值,超出阈值的内容自动写入临时文件:PDDocument.load(sourceFile, password, MemoryUsageSetting.setupMixed(100 * 1024 * 1024))
上述配置表示单块内容超过100M就写入临时文件,兼顾性能和内存安全。
报错截图参考:
内容的提问来源于stack exchange,提问作者Serendipity
相关产品推荐
相关产品推荐

