4

Jasperレポートを管理および実行するためのWebアプリを作成しました。最近、非常に大きな(1500ページ以上)出力を生成するいくつかのレポートを処理し、結果として生じるメモリの問題を解決しようとしています。を発見しましたJRFileVirtualizer。これにより、非常に限られたメモリフットプリントでレポートを正常に実行できました。ただし、私のアプリケーションの機能の1つは、以前に実行したレポートからの出力ファイルを保存し、それらをさまざまな形式(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は実行可能ですが、アプリケーションが将来JRVirtualizerにわたって利用できるようになるわけではありません。レポート実行のソリューションでは、エクスポートに似たようなものがあることを期待しています。私は手を汚して、Jasper内部クラスのいくつかを拡張したいと思っていますが、明らかな理由から、理想的な解決策はJasper自体によって提供されるものです。

4

3 に答える 3

5

この質問を投稿してから、JasperSoftに機能リクエストを提出しました。フォローアップとして、そのJRVirtualizationHelper.setThreadVirtualizer方法を指摘されました。このメソッドを使用すると、現在のスレッドに関連付けられたJRVirtualizerを設定できます。これは、JasperPrintの逆シリアル化中に使用されます。

私はこれを私のプロジェクトでテストし、満足のいく結果を得ました。APIでの可視性は改善される可能性がありますが、私が存在したいと思っていた機能は実際に存在しているようです。

コードサンプル:

JRVirtualizer virtualizer = new JRSwapFileVirtualizer(1000, new JRSwapFile(reportFilePath, 2048, 1024), true);
JRVirtualizationHelper.setThreadVirtualizer(virtualizer);
于 2011-09-28T14:52:32.770 に答える
2

あなたの問題は、.jrprintがシリアル化されたJavaオブジェクトであり、完全に逆シリアル化する必要があることだと思います。どういうわけかそれを小さなファイルに分割し、エクスポート時に出力を連結する必要があります。

私の提案は少し複雑ですが、少なくともいくつかのケースではうまくいくかもしれないと思います。

  1. を使用してレポートに入力しますJRVirtualizer。インスタンスを返すメソッドを使用して、JasperPrintすべてを巨大な.jrprintにダンプしないようにします。
  2. を使用して内部エクスポートを実行しJRXmlExporterます。秘訣は、適切なsを使用して、各ページを個別JRExportParameterにエクスポートするようにJasperに指示することです(大量のファイルを含むディレクトリを回避するために、をコンテナとして使用できます)。ZipOutputStream
  3. 実際のエクスポートを行う場合は、JASPER_PRINT_LISTを使用します。リストの実装が怠惰JasperPrintであり、を使用してインスタンスを1つずつ作成することが重要ですJRPrintXmlLoader。そのため、すべてを一度にロードする必要はありません。

とにかく、Jasperソースコードを調べて、このアプローチが実行可能かどうかを確認する必要があります。

于 2011-09-26T22:19:30.763 に答える
0

あなたの質問とあなた自身の答えをありがとう。

しかし、私はあなたの解決策についてさらに質問があります:

このメソッドを使用して、現在のスレッドに関連付けられているインスタンスJRVirtualizationHelper.setThreadVirtualizerを設定するとおっしゃいました。JRSwapFileVirtualizerただし、以前に生成されたレポートをPDF / CSVファイルにエクスポートする必要があるため、GENERATEアクションとEXPORTアクションは、2つの別々のユーザークリックによって生成される可能性があるため、2つの別々のスレッドで実行されると思います。

では、なぜJRSwapFileVirtualizer2つのスレッドに単一のインスタンスを設定できるのでしょうか。単一サーバーのJVMを使用していますか?

于 2022-02-11T04:01:47.547 に答える