History | Log In     View a printable version of the current page.  
Issue Details (XML | Word | Printable)

Key: QB-2031
Type: Bug Bug
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Steve Luo
Reporter: Maikel vd Hurk
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
QuickBuild

Running out of heap space while parsing big Junit report

Created: 23/Apr/14 08:55 AM   Updated: 27/Apr/14 04:43 AM
Component/s: None
Affects Version/s: None
Fix Version/s: 5.1.23

Original Estimate: Unknown Remaining Estimate: Unknown Time Spent: Unknown


 All   Comments   Work Log   Change History      Sort Order:
Maikel vd Hurk [23/Apr/14 08:58 AM]
Hitted by accident enter, but the problem is that nodes are reporting:
{noformat}
java.lang.RuntimeException: java.lang.OutOfMemoryError: Java heap space
        at com.pmease.quickbuild.bootstrap.BootstrapUtils.wrapAsUnchecked(BootstrapUtils.java:58)
        at com.pmease.quickbuild.util.ExceptionUtils.wrapAsUnchecked(ExceptionUtils.java:82)
        at com.pmease.quickbuild.stepsupport.Step.execute(Step.java:549)
        at com.pmease.quickbuild.stepsupport.StepExecutionJob.executeStepAwareJob(StepExecutionJob.java:30)
        at com.pmease.quickbuild.stepsupport.StepAwareJob.executeBuildAwareJob(StepAwareJob.java:45)
        at com.pmease.quickbuild.BuildAwareJob.execute(BuildAwareJob.java:60)
        at com.pmease.quickbuild.grid.GridJob.run(GridJob.java:72)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
        at java.util.concurrent.FutureTask.run(FutureTask.java:138)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.OutOfMemoryError: Java heap space
        at java.util.Arrays.copyOf(Arrays.java:2882)
        at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:100)
        at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:390)
        at java.lang.StringBuffer.append(StringBuffer.java:224)
        at org.dom4j.io.SAXContentHandler.characters(SAXContentHandler.java:293)
        at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.characters(AbstractSAXParser.java:538)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:489)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:808)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
        at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
        at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
        at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
        at org.dom4j.io.SAXReader.read(SAXReader.java:465)
        at org.dom4j.io.SAXReader.read(SAXReader.java:343)
        at com.pmease.quickbuild.plugin.report.engine.util.XMLHelper.readXML(XMLHelper.java:213)
        at com.pmease.quickbuild.plugin.report.engine.util.XMLHelper.readXML(XMLHelper.java:232)
        at com.pmease.quickbuild.plugin.report.junit.TestCaseProcessor.processResource(TestCaseProcessor.java:30)
        at com.pmease.quickbuild.plugin.report.engine.generator.AbstractProcessor.doExecute(AbstractProcessor.java:81)
        at com.pmease.quickbuild.plugin.report.engine.generator.GenerateAction.execute(GenerateAction.java:42)
        at com.pmease.quickbuild.plugin.report.engine.generator.AbstractGenerator.doExecute(AbstractGenerator.java:43)
        at com.pmease.quickbuild.plugin.report.engine.generator.GenerateAction.execute(GenerateAction.java:42)
        at com.pmease.quickbuild.plugin.report.engine.generator.DefaultGenerator.generate(DefaultGenerator.java:37)
        at com.pmease.quickbuild.plugin.report.engine.contribution.publisher.AbstractPublisher.doPublish(AbstractPublisher.java:162)
        at com.pmease.quickbuild.plugin.report.junit.JUnitPublisher$$EnhancerByCGLIB$$7095404f.CGLIB$doPublish$38(<generated>)
        at com.pmease.quickbuild.plugin.report.junit.JUnitPublisher$$EnhancerByCGLIB$$7095404f$$FastClassByCGLIB$$ca260f45.invoke(<generated>)
        at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:215)
        at com.pmease.quickbuild.DefaultScriptEngine$Interpolator.intercept(DefaultScriptEngine.java:273)
        at com.pmease.quickbuild.plugin.report.junit.JUnitPublisher$$EnhancerByCGLIB$$7095404f.doPublish(<generated>)
        at com.pmease.quickbuild.plugin.report.engine.contribution.publisher.AbstractPublisher.run(AbstractPublisher.java:129)
        at com.pmease.quickbuild.plugin.report.junit.JUnitPublisher$$EnhancerByCGLIB$$7095404f.CGLIB$run$31(<generated>)
        at com.pmease.quickbuild.plugin.report.junit.JUnitPublisher$$EnhancerByCGLIB$$7095404f$$FastClassByCGLIB$$ca260f45.invoke(<generated>)
        at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:215)
{noformat}

This is if the file is > 88MB. This could be solved by not loading everything in memory as only relevant data is the result data, not the 'system-out' and 'system-err' attribute which can be rather big, which is possible with the SAX parser which is used.

Steve Luo [24/Apr/14 03:16 AM]
Please edit wrapper.conf under ${quickbuild-home}/conf/ to increase your JVM memory like below:

wrapper.java.maxmemory=512



Maikel vd Hurk [24/Apr/14 05:50 AM]
Steve I know that this is possible solution, but in case there will be more system out / system err logging and file is growing I keep on increasing this maxmemory value. There is no added value in reading in the system attributes as for the JUnit report you require only the result data right?

Maikel vd Hurk [24/Apr/14 06:21 AM]
BTW maxmemory setting is already on 1024 and that is still not sufficient.

Maybe good to notice it is worth to look into: https://github.com/whummer/scaleDOM which has small memory footprint due to lazy loading of XML nodes. It only keeps a portion of the XML document in memory and re-loads nodes from the source file when necessary.

Steve Luo [24/Apr/14 07:18 AM]
Hi Maikel,

Thank you very much for the suggestion. But to change to another streaming API parser (like XPP) to parse the huge XML document may impact too many things in current report system. We can't do this in a short term as in our system, the report parser (not only for JUnit, but also for all other reports) are greatly relied on XPath which need loading the whole document into the system.

Back to your case, I want to know what is your builder, Ant or Maven? And is it possible for you to publish the JUnit reports for each testsuite instead of an aggregated report, so we can reduce the XML report size.

If you are using Maven, the surefire reports is what I mean. But if you are using Ant, you can try publish the test case XML reports instead of the aggregated one. That is, you needn't add JUnitReport task to aggregate the individual test suite report.

Maikel vd Hurk [24/Apr/14 07:39 AM]
It is based on ant junit report, and it is XML of single testsuite. We have quite a large amount of logging which is being exposed in system-out/system-err always that is why the XML is that big.

Steve Luo [24/Apr/14 09:16 AM]
You can specify option: outputtoformatters="false" to ignore sending the output to XML file, see below page:

http://ant.apache.org/manual/Tasks/junit.html


Steve Luo [24/Apr/14 09:21 AM]
Note, this option for junit task is added since Ant 1.7.0

Maikel vd Hurk [24/Apr/14 09:22 AM]
I know about that option, but we would like to have all information in single files available. There is no way that you don't load whole XML in memory? According to stacktrace you are using SAXParser which is able to load not all elements in memory when opening file in contradiction to dom.

Steve Luo [24/Apr/14 09:46 AM]
Even the system-out and system-err is in the XML, QuickBuild can't store them per issue QB-2001.

Sorry, I have no any idea now. Yes, we are using dom4j SAXReader, but as aforementioned, we are using XPath and it requires to construct the document tree in the memory so the whole document will be loaded to the memory. I haven't found any solution to do this, if you know, please let me know.


Steve Luo [24/Apr/14 12:07 PM]
Never mind, I think I found the solution now and will get it fixed in next patch release.

Steve Luo [24/Apr/14 04:37 PM]
Sorry, I have to update a bit more.

The memory needed in my solution depends on the max size of system-out or system-err element (in your case, these two elements may contain large of data) in your report.

For example, if you have a JUnit report XML file with 1G size, but each system-out or system-err is small, say, 20M, then QuickBuild may only need about 512M memory. While although your report file is only 100M, there is only one system-out or system-err which contains 90M data, QuickBuild may need about 1G memory to process it.

Now, the main issue is not caused by QuickBuild, instead, it is more related to how JDK processing String data in my opinion. A small test for this issue is below:

StringBuffer sb = new StringBuffer();
for (int i = 0; i < 1024 * 1024 * 128; i++)
    sb.append("a");

here, we want to create a 128M data in memory, you will find that you may need about 512M memory or even more.

Anyway, I'll include my solution in next patch release and hope that can handle most of your case.


Maikel vd Hurk [25/Apr/14 02:21 PM]
Thanks for the investigation and comment about it. The stringbuffer problem is known problem in Java, as well listed in bugs on at least 1.6 as far as I know.