java - Jasper 在导出时报告 OutOfMemoryError

标签 java jasper-reports out-of-memory export-to-csv

我编写了一个用于管理和运行 Jasper 报告的 Web 应用程序。最近我一直在处理一些生成非常大(1500 多页)输出的报告,并试图解决由此产生的内存问题。我发现了 JRFileVirtualizer ,这让我能够以非常有限的内存占用成功运行报告。但是,我的应用程序的一个特性是它存储以前运行的报告的输出文件,并允许将它们导出为各种格式(PDF、CSV 等)。因此,我发现自己有一个 500+MB 的 .jrprint 文件,并希望按需将其导出为 CSV 等格式。下面是一些简化的示例代码:

JRCsvExporter exporter = new JRCsvExporter();
exporter.setParameter(JRExporterParameter.INPUT_FILE_NAME, jrprintPath);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, outputStream);
exporter.exportReport();

不幸的是,当我在我提到的大文件上尝试这样做时,我得到了一个OutOfMemoryError:

Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded
    at java.io.ObjectInputStream$HandleTable.grow(ObjectInputStream.java:3421)
    at java.io.ObjectInputStream$HandleTable.assign(ObjectInputStream.java:3227)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1744)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
    at java.util.ArrayList.readObject(ArrayList.java:593)
    at sun.reflect.GeneratedMethodAccessor184.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:974)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1849)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
    at net.sf.jasperreports.engine.base.JRVirtualPrintPage.readObject(JRVirtualPrintPage.java:423)
    ...

从浏览一些 Jasper 内部结构来看,无论我如何尝试设置这个导出(我也尝试过直接加载和设置 JASPER_PRINT 参数),最终都会有一个调用 JRLoader.loadObject(...),它将尝试将我的整个 500MB 报告加载到内存中(参见 net.sf.jasperreports.engine.JRAbstractExporter.setInput() ).

我的问题是,有没有解决这个问题的方法,而不是仅仅用内存来解决这个问题? 500MB 是可行的,但它并不能使我的应用程序非常适合 future ,而且用于报告执行的 JRVirtualizer 解决方案让我希望有类似的东西用于导出。我愿意亲自动手并扩展一些 Jasper 内部类,但理想的解决方案是 Jasper 本身提供的解决方案,原因很明显。

最佳答案

自发布此问题以来,我还提交了一个 feature request与 JasperSoft。作为后续行动,我被指向了 JRVirtualizationHelper.setThreadVirtualizer方法。此方法允许您设置与当前线程关联的 JRVirtualizer,它将在 JasperPrint 反序列化期间使用。

我已经在我的项目中对此进行了测试,结果令人满意。看来我希望存在的功能确实存在,尽管它在 API 中的可见性可能会得到改善。

代码示例:

JRVirtualizer virtualizer = new JRSwapFileVirtualizer(1000, new JRSwapFile(reportFilePath, 2048, 1024), true);
JRVirtualizationHelper.setThreadVirtualizer(virtualizer);

关于java - Jasper 在导出时报告 OutOfMemoryError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7560499/

相关文章:

out-of-memory - Pytorch RuntimeError : CUDA error: out of memory at loss.backward(),使用CPU时没有错误

java - Coldfusion 到 Rails 的迁移,Java 代码保持不变

excel - 从 JasperViewer 保存到 Excel

java - jasper 报告中同一页两侧的拆分表

jasper-reports - 我们可以以分页方式向 jasper 提供数据吗?

Java VisualVM 从 tomcat 获取 HeapDump 但 Tomcat 未在本地应用程序下列出

java - 逐个字符搜索 Char

java - 使用jSTL向jsp传递一组参数包括

java - 使用 Java 8 安装 Dynamic Code Evolution VM (DCE) 时出错

java stackoverflowerror 在无限循环中抛出