ForEachHandler OutOfMemoryError
From Foochal
Stacktrace
I was trying to use a <c:forEach> loop in a facelet .xhtml file. I got this stacktrace.
Caused by: java.lang.OutOfMemoryError: Java heap space at com.sun.facelets.tag.jstl.core.ForEachHandler.apply(ForEachHandler.java:123) at com.sun.facelets.tag.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:47) at com.sun.facelets.tag.jstl.core.ChooseWhenHandler.apply(ChooseWhenHandler.java:45) at com.sun.facelets.tag.jstl.core.ChooseHandler.apply(ChooseHandler.java:68) at com.sun.facelets.tag.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:47) at com.sun.facelets.tag.ui.DefineHandler.applyDefinition(DefineHandler.java:64) at com.sun.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:131) at com.sun.facelets.impl.DefaultFaceletContext$TemplateManager.apply(DefaultFaceletContext.java:310) at com.sun.facelets.impl.DefaultFaceletContext.includeDefinition(DefaultFaceletContext.java:280) at com.sun.facelets.tag.ui.InsertHandler.apply(InsertHandler.java:68) at com.sun.facelets.tag.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:47) at com.sun.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:49) at com.sun.facelets.tag.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:47) at com.sun.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:25) at com.sun.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:248) at com.sun.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:294) at com.sun.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:273) at com.sun.facelets.impl.DefaultFaceletContext.includeFacelet(DefaultFaceletContext.java:144) at com.sun.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:113) at com.sun.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:49) at com.sun.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:25) at com.sun.facelets.impl.DefaultFacelet.apply(DefaultFacelet.java:95) at com.sun.facelets.FaceletViewHandler.buildView(FaceletViewHandler.java:524) at com.sun.facelets.FaceletViewHandler.renderView(FaceletViewHandler.java:567) at org.ajax4jsf.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:108) at org.ajax4jsf.application.AjaxViewHandler.renderView(AjaxViewHandler.java:189) at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:106) at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:251) at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:144) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:245) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
Solution
This error occurs when there is no "items" specified in the <c:forEach> tag
Analysis
I set a breakpoint on the in ForEachHandler.java file, where the error occurred and found that the code was trying to instantiate a very large array.
int s = this.getBegin(ctx); int e = this.getEnd(ctx); int m = this.getStep(ctx);
byte[] b = new byte[e + 1];
Here s=0, e=2147483646 and m=1. This explains the OutOfMemoryError. The question now arises: why is e such a large number.
I stepped into the getEnd() code:
private final int getEnd(FaceletContext ctx) {
if (this.end != null) {
return this.end.getInt(ctx);
}
return Integer.MAX_VALUE - 1; //hotspot bug in the JVM
}
It turns out that: this.end = null, this.begin = null, this.items = null. So basically, the forEach loop handler is unable to read the list and sets a default very high loop count. The next question is why is 'items' null?
I looked at my xhtml and discovered that accidentally when I changed the code from <ui:repeat> to <c:forEach> I forgot to change the loop contruct from "value" to "items"
<c:forEach value="#{myBean.books}">
It should be:
<c:forEach items="#{myBean.books}">

