在处理几百页的大文档时, Java 堆内存会不足,导致服务中断,请问可以怎么优化?
总内存大小是471872K
不确定是哪里的代码导致内存溢出。猜测应该是获取表格的代码:
public static List<TableBo> getDocumentTables(Document doc) {
LayoutCollector layoutCollector = new LayoutCollector(doc);
List<TableBo> tableList = new ArrayList<>(DocConstants.NUM_16);
for (Section section : doc.getSections()) {
for (Table table : section.getBody().getTables()) {
CompositeNode tableAncestor = table.getAncestor(NodeType.TABLE);
if (Objects.isNull(tableAncestor)) {
tableList.add(getTableBo(table, layoutCollector));
}
}
}
return tableList;
}
public static TableBo getTableBo(Table table, LayoutCollector layoutCollector) {
// 设置表格内容
return setTableContent(table, layoutCollector);
}
private static TableBo setTableContent(Table table, LayoutCollector layoutCollector) {
TableBo tableBo = new TableBo();
TableHeadingBo tableHeading = AsposeWordTableUtil.getTableHeading(table);
tableBo.setHeadingFirst(tableHeading.getHeadingFirst());
tableBo.setHeadingEnd(tableHeading.getHeadingEnd());
Row firstRow = table.getFirstRow();
if (Objects.nonNull(firstRow)) {
tableBo.setFirstRowIsHeadingFormat(firstRow.getRowFormat().getHeadingFormat());
}
tableBo.setFirstRow(firstRow);
// 需解决计算合并时多出现的列问题(表头+内容),若存在一列全为合并至上已列,则删除第二列
if (!isAlreadyMerged(table)) {
table.convertToHorizontallyMergedCells();
}
removeMergedColumns(table);
List<CellBo> tableHeader = getTableHeaderCells(firstRow);
tableBo.setTableHeader(tableHeader);
tableBo.setTable(table);
String tableTitle = queryTableTitle(table, tableBo);
tableBo.setTableTitle(tableTitle);
String tableNumber = queryTitleNumber(tableTitle);
String titleLabel = queryTitleLabel(tableTitle, tableNumber);
tableNumber = StringUtils.isNotBlank(titleLabel) ? titleLabel.replaceAll("[一-龥]", DocConstants.EMPTY) : tableNumber;
tableBo.setTitleNumber(tableNumber);
String removeLastSpace = StringUtil.removeTrailingChars(titleLabel);
if (StringUtils.isNotBlank(StringUtils.getDigits(removeLastSpace))) {
titleLabel = removeLastSpace;
}
tableBo.setTitleLabelSource(titleLabel);
titleLabel = titleLabel.replace(DocConstants.SPACE, DocConstants.EMPTY);
tableBo.setTitleLabel(titleLabel);
tableBo.setTitleContent(queryTitleContent(tableTitle, tableBo.getTitleLabelSource()));
if (StringUtils.isNotBlank(tableNumber)) {
String[] split = tableNumber.replaceAll("[-_\u001E-]", ".").split("\\.");
if (split.length >= DocConstants.NUM_2) {
tableBo.setTitleNumPrefix(split[DocConstants.NUM_0]);
tableBo.setTitleNumSuffix(split[DocConstants.NUM_1]);
}
if (split.length == DocConstants.NUM_1) {
tableBo.setTitleNumSuffix(split[DocConstants.NUM_0]);
}
}
if (Objects.nonNull(layoutCollector)) {
tableBo.setTableSpanNumber(AsposeWordUtil.getNodeSpan(layoutCollector, table));
tableBo.setTableSpan(tableBo.getTableSpanNumber() > DocConstants.NUM_0);
if (tableBo.isTableSpan()) {
Row row = tableSpreadRow(layoutCollector, table);
tableBo.setRowSpan(row);
}
}
tableBo.setTableHeader(tableHeader);
// 表格位置
WordParaLocationDto tableLocation = new WordParaLocationDto();
SearchCallback.setNodeInfo(table, tableLocation);
tableBo.setTableIndex(tableLocation.getTableIndex());
tableBo.setSectionIndex(tableLocation.getSectionIndex());
tableBo.setTableBelowMark(AsposeWordUtil.getNodeMark(table));
tableBo.setTableInternalMark(getTableMark(tableBo));
return tableBo;
}
请问使用 DocumentVisitor代替上面的处理表格的方式,是不是可以减少内存的溢出
@ouchli 您能否在此处附加您的文档以供测试?我们将检查问题并为您提供更多信息。您是否尝试过增加 java 堆空间?为了在处理极大文档时减少内存使用量,您可以尝试使用 LoadOptions.TempFolder 、 SaveOptions.TempFolder 和 SaveOptions.MemoryOptimization 属性。
请注意,Aspose.Words 分配的内存总是比实际文档大小多。这是意料之中的。请参阅我们的文档了解更多信息:https://docs.aspose.com/words/net/memory-requirements/
@ouchli 如果您正在保存一个非常大的文档(数千页)和/或同时处理许多文档,那么保存过程中的内存峰值可能会很大,足以导致系统抛出OutOfMemoryException。使用 TempFolder 指定临时文件夹会使 Aspose.Words 将内部结构保存在临时文件中,而不是内存中。这将减少保存过程中的内存使用量,但会降低保存性能。
文件夹必须存在且可写,否则会出现异常。此外,保存完成后,Aspose.Words 会自动删除所有临时文件。
例如
LoadOptions options = new LoadOptions();
options.setTempFolder("temp");
Document doc = new Document("input.docx");
OoxmlSaveOptions saveOptions = new OoxmlSaveOptions();
saveOptions.setTempFolder("temp");
doc.save("output.docx", saveOptions);
setMemoryOptimization "仅用于保存到 PDF 文件。
如果没有任何帮助,我们可以建议您增加 Java 堆空间大小。
那如果是在读取和解析 非常大的文档,占用内存大的时候这种方式应该没有用吧?