Apache PDFBOX - получение java.lang.OutOfMemoryError при использовании split(документ PDDocument)
Я пытаюсь разделить документ с приличными 300 страницами, используя Apache PDFBOX API V2.0.2. При попытке разделить файл PDF на отдельные страницы, используя следующий код:
PDDocument document = PDDocument.load(inputFile);
Splitter splitter = new Splitter();
List<PDDocument> splittedDocuments = splitter.split(document); //Exception happens here
Я получаю следующее исключение
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
Что указывает на то, что GC тратит много времени на очистку кучи, которая не оправдывается возвращенной суммой.
Существует множество методов настройки JVM, которые могут разрешить ситуацию, однако все они - только лечение симптома, а не реальная проблема.
И последнее замечание: я использую JDK6, поэтому в моем случае использование нового java 8 Consumer не вариант. Спасибо
Редактировать:
Это не повторяющийся вопрос http://stackru.com/questions/37771252/splitting-a-pdf-results-in-very-large-pdf-documents-with-pdfbox-2-0-2:
1. У меня нет проблемы размера, упомянутой в вышеупомянутом тема. Я нарезаю PDF-файл объемом 13,8 МБ на 270 страниц и после нарезки размер каждого среза составляет в среднем 80 КБ с общим размером 30.7MB. 2. Split создает исключение даже до того, как возвращает разделенные части.
Я обнаружил, что разделение может проходить до тех пор, пока я не передаю весь документ, вместо этого я передаю его как "Пакеты" по 20-30 страниц каждая, что и делает свою работу.
1 ответ
PDF Box хранит детали, полученные в результате операции разбиения, как объекты типа PDDocument в куче как объекты, что приводит к быстрому заполнению кучи, и даже если вы вызываете операцию close() после каждого цикла в цикле, GC все равно будет не сможет восстановить размер кучи так же, как он заполняется.
Можно разделить операцию разделения документа на пакеты, в которых каждый пакет представляет собой относительно управляемый блок (от 10 до 40 страниц).
public void execute() {
File inputFile = new File(path/to/the/file.pdf);
PDDocument document = null;
try {
document = PDDocument.load(inputFile);
int start = 1;
int end = 1;
int batchSize = 50;
int finalBatchSize = document.getNumberOfPages() % batchSize;
int noOfBatches = document.getNumberOfPages() / batchSize;
for (int i = 1; i <= noOfBatches; i++) {
start = end;
end = start + batchSize;
System.out.println("Batch: " + i + " start: " + start + " end: " + end);
split(document, start, end);
}
// handling the remaining
start = end;
end += finalBatchSize;
System.out.println("Final Batch start: " + start + " end: " + end);
split(document, start, end);
} catch (IOException e) {
e.printStackTrace();
} finally {
//close the document
}
}
private void split(PDDocument document, int start, int end) throws IOException {
List<File> fileList = new ArrayList<File>();
Splitter splitter = new Splitter();
splitter.setStartPage(start);
splitter.setEndPage(end);
List<PDDocument> splittedDocuments = splitter.split(document);
String outputPath = Config.INSTANCE.getProperty("outputPath");
PDFTextStripper stripper = new PDFTextStripper();
for (int index = 0; index < splittedDocuments.size(); index++) {
String pdfFullPath = document.getDocumentInformation().getTitle() + index + start+ ".pdf";
PDDocument splittedDocument = splittedDocuments.get(index);
splittedDocument.save(pdfFullPath);
}
}