PDFBox 3.0.0添加文档保护时触发OutOfMemoryError问题咨询
内存占用过高的原因与解决方案
核心原因
PDFBox 的 protect() 方法在默认内存配置下,会将整个PDF的所有对象加载到JVM堆内存中完成加密操作。你的221MB原始PDF,加上加密过程中生成的临时对象(如加密后的字节数组、对象副本、加密运算缓存等),实际内存占用会远超过文件本身大小,512MB的堆内存不足以容纳这些数据,从而引发内存溢出或过高占用。
而当你不调用protect()时,PDFBox保存文档采用的是流式处理逻辑,无需将全量数据加载到堆中;使用MemoryUsageSetting.setupTempFileOnly()时,PDFBox会把加密所需的临时数据写入磁盘临时文件,仅在堆中保留少量元数据,因此内存占用可控。
解决方案
1. 强制在文档加载阶段启用磁盘缓存
在加载PDF文档时就指定MemoryUsageSetting.setupTempFileOnly(),确保加密全流程都使用磁盘存储临时数据,而不是堆内存:
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.encryption.AccessPermission; import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy; import org.apache.pdfbox.io.MemoryUsageSetting; import java.io.File; import java.io.IOException; public class PDFEncryptor { public static void main(String[] args) { // 配置仅使用临时文件存储,不占用堆内存 MemoryUsageSetting memorySetting = MemoryUsageSetting.setupTempFileOnly(); try (PDDocument inDoc = PDDocument.load(new File("input.pdf"), memorySetting)) { AccessPermission accessPerm = new AccessPermission(); accessPerm.setCanModify(false); // 禁用修改权限 StandardProtectionPolicy protectionPolicy = new StandardProtectionPolicy( "owner_password", // 所有者密码(用于修改文档) "user_password", // 用户密码(用于打开文档) accessPerm ); // 可选:指定加密密钥长度,128位比256位内存开销略小 protectionPolicy.setEncryptionKeyLength(128); inDoc.protect(protectionPolicy); inDoc.save("output.pdf"); } catch (IOException e) { e.printStackTrace(); } } }
2. 调整JVM堆内存(临时方案)
如果磁盘缓存方案因环境限制无法使用,可以尝试调高堆内存上限,比如设置-Xmx1024m(1GB),给加密过程足够的堆空间,但这种方案不如磁盘缓存高效,且大文件场景下仍可能出现问题。
3. 升级PDFBox版本
你使用的是3.0.0-RC1候选版本,可能存在内存优化方面的bug。建议升级到PDFBox 3.x正式版,官方后续版本通常会修复RC版本中的内存泄漏或低效问题。
注意事项
- 确保临时文件目录有足够的磁盘空间(至少是原PDF文件大小的2-3倍)。
- 始终使用try-with-resources语法管理
PDDocument对象,确保资源及时释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

