Mesclando 1000 PDF através iText lança java.lang.OutOfMemoryError: Espaço Java heap
-
12-09-2019 - |
Pergunta
Eu estou tentando mesclar arquivos PDF 1000 através iText. Eu não estou certo de onde o vazamento de memória está acontecendo. Abaixo está o código de exemplo. Note que eu estou removendo o arquivo filho-pdf assim que se fundem para o arquivo principal. Por favor pointout bug no código abaixo ou há alguma maneira melhor de fazer isso com a concepção de memória. Este processo é feito através de servlet (não autônomo programa)
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();
Solução
Você pode querer tentar algo como o seguinte (a manipulação de exceção, fechar arquivo e apagar removido para maior clareza):
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();
Outras dicas
Quem diz que há um vazamento de memória? Suas necessidades documento mesclado para caber na memória em sua totalidade, não há nenhuma maneira em torno dela, e pode muito bem ser maior do que o tamanho da pilha padrão de 64MB na memória (em vez de no disco).
Eu não vejo um problema com o seu código, mas se você quiser diagnosticá-la em detalhe, uso de VisualVM pilha profiler (vem com o JDK desde Java 6 update 10 ou assim).
Você tentou aumentar tamanho da pilha máximo do padrão (que é apenas 64mb)?
Veja:
E se você não usar InputStream? Se você puder, tente usar apenas o caminho para você arquivo em 'nova PdfReader ( '/ algumdiretorio / arquivo.').
Isto faz o leitor a agir no disco.
O código acima está tentando criar um objeto PdfContentByte
(cb
) dentro do loop. Movê-lo fora pode corrigir o problema. I utilizado código semelhante no meu aplicativo para unir 13k PDFs individuais em que um PDF sem problemas.
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");
}
}
}
Em vez de juntar 1000 PDFs, tente criar um zip deles.