在处理几百页的大文档时, Java 堆内存会不足,导致服务中断,请问可以怎么优化?

在处理几百页的大文档时, Java 堆内存会不足,导致服务中断,请问可以怎么优化?

@ouchli

请问您能否提供更多关于您使用的代码和具体的内存设置的信息?

总内存大小是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.TempFolderSaveOptions.TempFolderSaveOptions.MemoryOptimization 属性。

请注意,Aspose.Words 分配的内存总是比实际文档大小多。这是意料之中的。请参阅我们的文档了解更多信息:https://docs.aspose.com/words/net/memory-requirements/

LoadOptions.TempFolderSaveOptions.TempFolderSaveOptions.MemoryOptimization 属性
请问上述属性应该如何使用呢?

@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 堆空间大小。

那如果是在读取和解析 非常大的文档,占用内存大的时候这种方式应该没有用吧?

@ouchli 是的,该选项主要用于加载/保存文档,而不是处理。如果可能的话,请提供可以重现该问题的文件示例应用程序。我们将对此进行调查,并尝试提供一些补充信息。