[#4151] - So many instance of JRTemplatePrintText, SimpleTextFormat and JRTemplatePrintFrame

Category:
Bug report
Priority:
Immediate
Status:
Feedback Requested
Project: Severity:
Block
Resolution:
Open
Component: Reproducibility:
Sometimes
Assigned to:
1

I'm troubleshuting the RAM usage of jasper library (using jmap -histo) and realize that there are so many instances of JRTemplatePrintText, SimpleTextFormat and JRTemplatePrintFrame:

num #instances #bytes class name
----------------------------------------------
1: 7034450 844134000 net.sf.jasperreports.engine.fill.JRTemplatePrintText
2: 8586233 256002896 [C
3: 8585462 206051088 java.lang.String
4: 1476040 96613168 [Ljava.lang.Object;
5: 2813773 90040736 net.sf.jasperreports.engine.fill.SimpleTextFormat
6: 1406890 67530720 net.sf.jasperreports.engine.fill.JRTemplatePrintFrame
7: 1429612 45747584 java.util.HashMap$Entry
8: 1406889 45020448 net.sf.jasperreports.engine.util.LinkedMap$LinkedValue
9: 1414013 33936312 java.util.ArrayList
10: 1406886 33765264 net.sf.jasperreports.engine.fill.ElementEvaluationAction
11: 1409016 22544256 java.lang.Integer
12: 1892 8958152 [Ljava.util.HashMap$Entry;
13: 49949 7594672 <constMethodKlass>
....................

Can anyone explain for me why we need to use so many these duplicated instances? What is the meaning of them? I think it should be small (around 1-100 instances) since I only have some templates.

v5.0.1
dthnam90's picture
Joined: May 24 2013 - 1:35am
Last seen: 2 years 4 days ago

13 Comments:

#1
  • Reproducibility:N/A» Always
#2
  • Assigned:nobody»

A JRTemplatePrintText instance corresponds to a text element present in the generated document. So if your report generates a document with 100 pages and each page has 200 texts on it, you'll have 20,000 JRTemplatePrintText instances.

If heap usage is a concern, you can look into using a virtualizer for the report.

I would also suggest trying a more recent JR version.

Regards,
Lucian

#3
  • Assigned:» anonymous

Hi Lucian,

I used virtualizer, the swap file is about 700MB. At the end of report filling, it still need to read back from the swap file to build the final JasperPrint object and it consumed about 5GB RAM.
I tried to log all JRTemplatePrintText instances and saw that all of them are identical, then I also tried to modify some classes of Jasper code to cache JRTemplatePrintText and only create a new instance of JRTemplatePrintText if it does not exist, and the result is better: the swap is only about 200MB and RAM is only about 3GB.
There are many class have the similar issue: SimpleTextFormat, JRTemplatePrintFrame…etc. I’m wondering should we need a cache and only create new instance if it is NOT in the cache?
Attached zip file is what I have modified on Jasper code (Jasper 5.0.1), you can compare old and new folder to see the differences. Let me know your ideas?

Thanks,
Nam Dam

AttachmentSize
Package icon jasperreport.zip47.49 KB
#4

I'm repeating my suggestion to try a newer JR, there have been some improvements with memory consumption and virtualization.

And I don't understand the part about "reading back from the swap file". A virtualized report does not need to be "read back" into memory, the idea is that it stays virtualized during its entire lifecycle. Could you clarify what exactly you are doing with the report?

#5

Thanks Lucian for the help, I upgraded to the latest jasper (6.0.0), but the result is not better.
Let me clarify more details about my words “read back”:
I have a report with 4 sub-reports are nested together. E.g. sub-report 1 contain sub-report 2, sub-report 2 contain sub-report 3…etc. At the beginning of the filling, I add a virtualizer to JasperDesign, my virtualizer is similar as below:

public class MyVirtualizer extends JRSwapFileVirtualizer {
private static final int PAGES_IN_MEMORY = 1000;

public MyVirtualizer() {
super(PAGES_IN_MEMORY, makeSwapFile(), true);
}

private static JRSwapFile makeSwapFile() {
Calendar cal = Calendar.getInstance();
cal.set(cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH),
cal.get(Calendar.DAY_OF_MONTH),
0, 0, 0);
cal.set(Calendar.MILLISECOND, 0);

File swapFileDir = new File(
"C://jasperreports//swap//" + cal.getTimeInMillis()
);

if (!swapFileDir.exists())
swapFileDir.mkdirs();

return new JRSwapFile(swapFileDir.getAbsolutePath(), 1024, 100);
}
}

At the beginning of the filling, I saw that the virtualizer created a swap file, and this file will be written if the number of page is greater than the PAGES_IN_MEMORY which I set in the above code.
At sub-report 3 filling, the virtualizer start to write to swap file, the memory at that time is about 3G. The swap file grows quickly to 600 MB.
At sub-report 4 filling, the virtualizer continue to write to swap file but just a little. Memory is still about 3G.
At the end of main-report filling, the swap file is released and the memory is consumed about 5G. That is why I think that the virtualizer has a step to “read back” from swap to memory.

Below is my implementation:
1. I build a web that allow users to input their report template dynamically.
2. I build a Jasper Design based on user inputs. Also create a virtualizer for this Jasper Design.
3. Then let Jasper side to compile Jasper Design to Jasper Report which is ready for the filling.
4. I use AsynchronousFillHandle as the fill handler. It will notify me when Jasper side finish the filling.
5. Start the fill handler. From here, the whole work will be jasper, I just listen to jasper to know if the filling process is completed.
6. When I receive the notification from jasper that the filling is done (At this time, the memory is about 5 GB), I will continue to write Jasper Print (which is ready for view/export) into a file (e.g. report.bin) to store somewhere.
7. Then every time users want to view/export their report, I will read from report.bin. With this implementation, users can view/export history report without re-execute that report. In additional, I can move report.bin to another server for the server balancing.

Let me know your ideas about my implementation, should I revise somewhere? I’m not only concern about memory but also the size of Jasper Print object, it consume about 870MB hard disk when I write it to report.bin using java serialization. My report is only about 5 pages.

#6

I'm waiting for you, Lucian :)

Thanks,
NamDam

#7
  • Priority:High» Immediate
  • Severity:Major» Block

Hi - do we have solution for this? Problems that I see are
1) net.sf.jasperreports.engine.fill.JRTemplatePrintText is not garbage collected after excel(xls) is downloaded
2) I do not use virtualizer and it does use java heap memory to generate a report
3) After i download excel (having 15 sheets of data) around 65000*15 - Huge amount of heap memory is occupied (around 3 GB) and causing memory leaks

#8
  • Reproducibility:Always» Sometimes

Hi,

We are running into the same issue of memory leak due to too many instances of JRTemplatePrintText.

Jasper Library : 6.2.0
JRXML Files : 1 Main and 15 Subreports
Application server : JBoss

When we run the report in Jasper Studio against the same data source, we have no problem, and PDF get rendered in few seconds.
However, rendering the same report through Jasper library in our Java application, causes OldGen memory block (4.5 GB) completely filled up, eventually crashing the server giving the following error.

GC overhead limit exceededjava.lang.OutOfMemoryError: GC overhead limit exceeded

Any feedback will be greatly appreciated.

Thanks

#9

Our problem resolved by implementing the solution given here :
http://community.jaspersoft.com/wiki/isprintwhendetailoverflowstrue-can-...

#10

Hi,

@dthnam90, was this related to a large number of empty zero-by-zero size elements in your report template?
In case it is, I would like to close this tracker here.

Thanks,
Teodor

#11
  • Status:New» Feedback Requested
  • Assigned:nobody» teodord
#12

We have been seeing the exact same behavior for a while now. In our case we're exporting a big CSV, we have swap to disk enabled and we tried the workaround linked "isPrintWhenDetailOverflows=false" on all report elements, we also tried with both pagination disabled and enabled. The swap file does get created and grows to maybe 2Gb.

Our app usually runs in less than 2Gb of RAM as long as we don't run reports. To be able to run reports we are now at -Xmx34816m (34G) and we're again hitting the limit, consuming all memory and crashing.

A heap analysis shows JRTemplatePrintText, JRTemplatePrintFrame and JRPropertiesMap consuming multiple gigs.

#13

I'm having the exact same issue, I'm using as dataset the result of a store procedure, the problem is I'm getting an out of memory error, and when that error does not happen, I notice memory in EDEN is 4gb, which is weird because nothing gets promoted to TENURED, analyzing the memory dump I got:

#Instances | class
2412617 net.sf.jasperreports.engine.JRPropertiesMap
2386637 net.sf.jasperreports.engine.fill.JRTemplatePrintFrame
2385761 net.sf.jasperreports.engine.fill.JRTemplatePrintText
1224214 net.sf.jasperreports.engine.JRPropertiesUtil

I'm using latest version of your library:

<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>6.7.0</version>

Still the error is the same; The funny part is that the memory is cleaned if I invoke the garbage collector explicitly.

Do any of you have found a solution to this?

AttachmentSize
Image icon after-gc.png101.37 KB
Feedback