Aspose.PDF for Java を使用した PDF 結合処理におけるメモリ使用量

【質問】
Document.getPages().add() による逐次結合以上にメモリ面で効率的な方法はありますか?

【現在の状況】
要件:処理対象:100MB × 5 個の PDF ファイル結合
実装:Document.getPages().add() による逐次結合
参考: プログラムによるPDFの結合|Aspose.PDF for Java
結果:Javaのヒープメモリの使用量が約900MB(理論値500MBの約2倍)

【その他、試行済みの方式】
PdfFileEditor.concatenate(ストリーム配列) → 約 2470MB
PdfFileEditor.concatenate(ファイルパス配列) → 約 2595MB
MemoryStream 逐次結合 → OutOfMemoryError
参考: PDF文書を連結する|Aspose.PDF for Java

@miyawaki

PDFファイルの結合処理において、Document.getPages().add() メソッドを使用すると、特に大きなPDFファイルを扱う際にメモリ使用量が高くなることがあります。効率的なメモリ管理が重要です。

以下の方法を試して、メモリ使用量を改善できるか確認してみてください:

  1. ストリームを使用する: PDFファイルを直接ファイルパスからではなく、ストリームを使用して結合することで、メモリの使用を抑えることができる場合があります。

  2. 分割処理: 大きなPDFファイルを小さな部分に分割し、それぞれを結合してから最終的に一つのPDFにまとめる方法も検討してみてください。

  3. ヒープメモリの増加: Javaのヒープメモリを増やすことで、OutOfMemoryErrorを回避できる場合があります。JVMの起動オプションで -Xmx を設定して、使用可能なメモリを増やしてみてください。

これらの方法を試して、メモリ使用量の改善が見られるか確認してみてください。

@miyawaki

お客様の側からもう少し情報をいただけると助かります。具体的には、サンプルファイル、コードスニペット、メモリ使用状況のスクリーンショットなどをご提供ください。また、最新バージョンのAPIを試されたかどうかもご確認ください。その後、適切なサポートを進めさせていただきます。

100MBのPDFファイルを10個準備し、C:\workspace\pdf_workspace\input\Concat1.pdfに配置しています。(連番でConcat10.pdfまで)
そして、サンプルコードをもとに10個を連結した場合に使用メモリが1400MB程度になります。
APIのバージョンは25.5です。

private static String _dataDir = "C:\\workspace\\pdf_workspace\\input\\";
@Test
public void testMergeTwoPdfFiles() throws Exception {
    // Aspose.PDFのバージョン情報を取得
    System.out.println("  ASSEMBLY_VERSION: " + BuildVersionInfo.ASSEMBLY_VERSION);
    License license = new License();
    license.setLicense("C:\\workspace\\pdf_workspace\\input\\Aspose.Pdf.Java.lic");
    System.out.println("10ファイル連結テスト開始");
    printHeapSize("連結処理前");
    // 最初のドキュメントを開く
    Document pdfDocument1 = new Document(_dataDir + "Concat1.pdf");
    printHeapSize("1つ目のファイル読み込み後");
    // 2番目から10番目のドキュメントを順次連結
    for (int i = 2; i <= 10; i++) {
        Document pdfDocument = new Document(_dataDir + "Concat" + i + ".pdf");
        printHeapSize(i + "つ目のファイル読み込み後");
        // ページを追加
        pdfDocument1.getPages().add(pdfDocument.getPages());
        printHeapSize(i + "つ目のファイル連結後");
    }
    // 連結された出力ファイルを保存
    pdfDocument1.save(_dataDir + "ConcatenatePdfFiles_out.pdf");
    printHeapSize("ファイル保存後");
    System.out.println("連結処理完了");
}
private void printHeapSize(String timing) {
    Runtime runtime = Runtime.getRuntime();
    long maxMemory = runtime.maxMemory(); // 最大ヒープサイズ
    long totalMemory = runtime.totalMemory(); // 現在の総ヒープサイズ
    long freeMemory = runtime.freeMemory(); // 使用可能メモリ
    long usedMemory = totalMemory - freeMemory; // 使用中メモリ
    // MB単位に変換
    double maxMB = maxMemory / (1024.0 * 1024.0);
    double totalMB = totalMemory / (1024.0 * 1024.0);
    double usedMB = usedMemory / (1024.0 * 1024.0);
    double freeMB = freeMemory / (1024.0 * 1024.0);
    System.out.printf("[%s] ヒープ使用状況:%n", timing);
    System.out.printf("  最大ヒープ: %.2f MB%n", maxMB);
    System.out.printf("  総ヒープ: %.2f MB%n", totalMB);
    System.out.printf("  使用中: %.2f MB (%.1f%%)%n", usedMB, (usedMB / maxMB) * 100);
    System.out.printf("  使用可能: %.2f MB%n", freeMB);
    System.out.println();
}

実行結果は下記です。

ASSEMBLY_VERSION: 25.5
10ファイル連結テスト開始
[連結処理前] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 1232.50 MB
使用中: 133.40 MB (0.9%)
使用可能: 1099.10 MB

[1つ目のファイル読み込み後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 1316.00 MB
使用中: 215.32 MB (1.5%)
使用可能: 1100.68 MB

[2つ目のファイル読み込み後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 1316.00 MB
使用中: 326.08 MB (2.2%)
使用可能: 989.92 MB

[2つ目のファイル連結後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 1316.00 MB
使用中: 435.84 MB (3.0%)
使用可能: 880.16 MB

[3つ目のファイル読み込み後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 1316.00 MB
使用中: 535.83 MB (3.7%)
使用可能: 780.17 MB

[3つ目のファイル連結後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 1316.00 MB
使用中: 635.83 MB (4.4%)
使用可能: 680.17 MB

[4つ目のファイル読み込み後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 1599.50 MB
使用中: 501.29 MB (3.5%)
使用可能: 1098.21 MB

[4つ目のファイル連結後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 1599.50 MB
使用中: 604.81 MB (4.2%)
使用可能: 994.69 MB

[5つ目のファイル読み込み後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 1599.50 MB
使用中: 708.33 MB (4.9%)
使用可能: 891.17 MB

[5つ目のファイル連結後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 1599.50 MB
使用中: 811.85 MB (5.6%)
使用可能: 787.65 MB

[6つ目のファイル読み込み後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 1599.50 MB
使用中: 911.84 MB (6.3%)
使用可能: 687.66 MB

[6つ目のファイル連結後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 1599.50 MB
使用中: 1011.84 MB (7.0%)
使用可能: 587.66 MB

[7つ目のファイル読み込み後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 1599.50 MB
使用中: 1111.83 MB (7.7%)
使用可能: 487.67 MB

[7つ目のファイル連結後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 1599.50 MB
使用中: 1211.83 MB (8.4%)
使用可能: 387.67 MB

[8つ目のファイル読み込み後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 2843.00 MB
使用中: 894.95 MB (6.2%)
使用可能: 1948.05 MB

[8つ目のファイル連結後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 2843.00 MB
使用中: 997.63 MB (6.9%)
使用可能: 1845.37 MB

[9つ目のファイル読み込み後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 2843.00 MB
使用中: 1097.63 MB (7.6%)
使用可能: 1745.37 MB

[9つ目のファイル連結後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 2843.00 MB
使用中: 1197.63 MB (8.3%)
使用可能: 1645.37 MB

[10つ目のファイル読み込み後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 2843.00 MB
使用中: 1302.52 MB (9.0%)
使用可能: 1540.48 MB

[10つ目のファイル連結後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 2843.00 MB
使用中: 1405.21 MB (9.7%)
使用可能: 1437.79 MB

[ファイル保存後] ヒープ使用状況:
最大ヒープ: 14500.00 MB
総ヒープ: 2843.00 MB
使用中: 1412.04 MB (9.7%)
使用可能: 1430.96 MB

連結処理完了

@miyawaki

弊社の内部課題管理システムに以下の新しいチケットを登録しました。これらの修正は、Free Support Policies に記載された条件に基づいて提供されます。

課題ID: PDFJAVA-45433

優先的なサポートが必要な場合は、Paid Support Services をご利用いただくことで、弊社の有料サポート管理チームへの直接アクセスが可能です。

ご対応ありがとうございます。
現時点では、提示した実装が最適なコーディングになりますでしょうか?

@miyawaki

はい、使用しているコードはDOMベースで推奨されるものです。APIの改善によってメモリ消費を最小化し、最適化できるかどうか調査し、チケットが解決次第お知らせいたします。少々お時間をいただけますようお願い申し上げます。

ご不便をおかけして申し訳ございません。