iText を介して 1000 PDF をマージすると、java.lang.OutOfMemoryError がスローされます。Java ヒープ領域
-
12-09-2019 - |
質問
iText を介して 1000 個の PDF ファイルを結合しようとしています。どこでメモリリークが発生しているのかわかりません。以下はサンプルコードです。親ファイルにマージしたらすぐに子 PDF ファイルを削除していることに注意してください。以下のコードのバグを指摘してください。あるいは、メモリの概念を使用せずにこれを行うより良い方法はありますか。このプロセスはサーブレットを通じて実行されます (スタンドアロン プログラムではありません)。
FileInputStream local_fis = null;
BufferedInputStream local_bis = null;
File localFileObj = null;
for(int taIdx=0;taIdx<totalSize;taIdx++){
frObj = (Form3AReportObject)reportRows.get(taIdx);
localfilename = companyId + "_" + frObj.empNumber + ".pdf";
local_fis = new FileInputStream(localfilename);
local_bis = new BufferedInputStream(local_fis);
pdfReader = new PdfReader(local_bis);
cb = pdfWriter.getDirectContent();
document.newPage();
page = pdfWriter.getImportedPage(pdfReader, 1);
cb.addTemplate(page, 0, 0);
local_bis.close();
local_fis.close();
localFileObj = new File(localfilename);
localFileObj.delete();
}
document.close();
解決
次のようなことを試してみるとよいでしょう (わかりやすくするために、例外処理、ファイルのクローズと削除を削除しました)。
for(int taIdx = 0; taIdx < totalSize; taIdx++) {
Form3AReportObject frObj = (Form3AReportObject)reportRows.get(taIdx);
localfilename = companyId + "_" + frObj.empNumber + ".pdf";
FileInputStream local_fis = new FileInputStream(localfilename);
pdfWriter.freeReader(new PdfReader(local_fis));
pdfWriter.flush();
}
pdfWriter.close();
他のヒント
メモリリークがあると誰が言ったでしょうか?マージされたドキュメントは全体がメモリに収まる必要がありますが、これを回避する方法はなく、デフォルトのヒープ サイズである 64 MB よりも大きくなる可能性があります。 記憶の中で (ディスク上ではなく)。
コードに問題はありませんが、詳細に診断したい場合は、 VisualVM のヒープ プロファイラーを使用する (Java 6 Update 10 以降には JDK が付属しています)。
最大ヒープ サイズをデフォルト (わずか 64 MB) から増やしてみましたか?
見る:
InputStream を使用しない場合はどうなるでしょうか?可能であれば、「new PDFReader("/somedirectory/file.") 上のファイルのパスだけを使用してみてください。
これにより、リーダーがディスク上で動作するようになります。
上記のコードは、 PdfContentByte
物体 (cb
) ループ内で。屋外に移動すると問題が解決する可能性があります。私はアプリケーションで同様のコードを使用して、13,000 個の個別の PDF を問題なく 1 つの PDF に結合しました。
public class PdfUtils {
public static void concatFiles(File file1, File file2, File fileOutput) throws Exception {
List<File> islist = new ArrayList<File>();
islist.add(file1);
islist.add(file2);
concatFiles(islist, fileOutput);
}
public static void concatFiles(List<File> filelist, File fileOutput) throws Exception {
if (filelist.size() > 0) {
PdfReader reader = new PdfReader(new FileInputStream( filelist.get(0)) );
Document document = new Document(reader.getPageSizeWithRotation(1));
PdfCopy cp = new PdfCopy(document, new FileOutputStream( fileOutput ));
document.open();
for (File file : filelist ) {
PdfReader r = new PdfReader( new FileInputStream( file));
for (int k = 1; k <= r.getNumberOfPages(); ++k) {
cp.addPage(cp.getImportedPage(r, k));
}
cp.freeReader(r);
}
cp.close();
document.close();
} else{
throw new Exception("La lista dei pdf da concatenare è vuota");
}
}
}
1,000 個の PDF を結合する代わりに、それらの PDF を作成してみてください。