Jasper reporta OutOfMemoryError na exportação
Eu escrevi um aplicativo Web para gerenciar e executar relatórios Jasper. Ultimamente, tenho trabalhado com alguns relatórios que geram saídas extremamente grandes (mais de 1500 páginas) e tentando resolver os problemas de memória resultantes. Eu descobri oJRFileVirtualizer
, o que me permitiu executar o relatório com sucesso, com um espaço de memória muito limitado. No entanto, um dos recursos do meu aplicativo é que ele armazena arquivos de saída de relatórios executados anteriormente e permite que eles sejam exportados para vários formatos (PDF, CSV, etc.). Portanto, encontro-me na situação de ter um arquivo .jrprint de 500 + MB e querer exportá-lo para, por exemplo, CSV sob demanda. Aqui está um exemplo de código simplificado:
JRCsvExporter exporter = new JRCsvExporter();
exporter.setParameter(JRExporterParameter.INPUT_FILE_NAME, jrprintPath);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, outputStream);
exporter.exportReport();
Infelizmente, quando tento fazer isso no arquivo grande que mencionei, recebo umOutOfMemoryError
:
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)
...
De navegar em alguns dos componentes internos do Jasper, parece que não importa como eu tente configurar essa exportação (eu também tentei carregar e definir oJASPER_PRINT
diretamente), haverá finalmente uma chamada paraJRLoader.loadObject(...)
, que tentará carregar todo o meu relatório de 500 MB na memória (consultenet.sf.jasperreports.engine.JRAbstractExporter.setInput()
).
Minha pergunta é: existe uma maneira de contornar isso que não envolve apenas jogar memória no problema? 500 MB é possível, mas não deixa meu aplicativo muito à prova de futuro, e oJRVirtualizer
solução @ para execução de relatórios me deixa esperando que exista algo semelhante para exportação. Estou disposto a sujar as mãos e estender algumas das classes internas do Jasper, mas a solução ideal seria uma fornecida pelo próprio Jasper, por razões óbvia