It surely consumes less stack this way, though stack usage doesn't used to be an concern (barring FTL sequence concatenations in a loop, but that's another topic). While less stack is just better regardless, with this change the code becomes a bit more convoluted (especially if you had to do something after the child elements ran; though if I saw well, surprisingly, we don't have such case so far). So I would like to understand why does your application need so deep stack. I would think that you had to have some ridiculously high number of things nested into each other to run into this, but maybe I'm wrong.
Thursday, September 10, 2015, 3:53:13 PM, Kleine, Moritz wrote: > Hi, > > we’re building a website using a view-agnostic document store and a > spring-based webapp that is capable of rendering views for documents > that include views of linked documents. The views are typically > small freemarker templates (at most some tenths of lines) using a > custom include directive that determines the view for the included > document and – if it is a freemarker template — tells that template to > process itself. > > Now, we’re frequently running into stackoverflowerrors which > exhibit the level of inclusion and the whole structure of the > freemarker templates from the root of up to the custom include. The > stacktrace fragment shown below ([1]) is taken from such a > stackoverflowerror. I’d suggest to adjust the visitor pattern based > implementation so that the accept calls do not invoke > Environment#visit again but return the tempate elements to be > visited. That way we obtain stacktraces that look as shown further > down below ([2]). The patched code resides here: > https://github.com/mkleine/incubator-freemarker/tree/avoid-too-much-recursion-when-visiting-template-elements > > Are we misusing freemarker or is the approach to reduction of stackframes > welcome? > > Kind regards, > Moritz > > > [1] > at > freemarker.ext.beans.BeansWrapper.invokeMethod(BeansWrapper.java:1458) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.ext.beans.SimpleMethodModel.exec(SimpleMethodModel.java:71) > [freemarker-2.3.22.jar:2.3.22] > at freemarker.core.MethodCall._eval(MethodCall.java:62) > [freemarker-2.3.22.jar:2.3.22] > at freemarker.core.Expression.eval(Expression.java:78) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.Expression.evalAndCoerceToString(Expression.java:82) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.BuiltInForString._eval(BuiltInForString.java:26) > [freemarker-2.3.22.jar:2.3.22] > at freemarker.core.Expression.eval(Expression.java:78) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.Expression.evalAndCoerceToString(Expression.java:82) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.DollarVariable.accept(DollarVariable.java:40) > [freemarker-2.3.22.jar:2.3.22] > at freemarker.core.Environment.visit(Environment.java:312) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.MixedContent.accept(MixedContent.java:62) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.Environment.visitByHiddingParent(Environment.java:333) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.ConditionalBlock.accept(ConditionalBlock.java:48) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.Environment.visitByHiddingParent(Environment.java:333) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.Environment.visitAndTransform(Environment.java:413) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.CompressedBlock.accept(CompressedBlock.java:37) > [freemarker-2.3.22.jar:2.3.22] > at freemarker.core.Environment.visit(Environment.java:312) > [freemarker-2.3.22.jar:2.3.22] > at freemarker.core.Macro$Context.runMacro(Macro.java:178) > [freemarker-2.3.22.jar:2.3.22] > at freemarker.core.Environment.invoke(Environment.java:700) > [freemarker-2.3.22.jar:2.3.22] > at freemarker.core.UnifiedCall.accept(UnifiedCall.java:84) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.Environment.visitByHiddingParent(Environment.java:333) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.IteratorBlock$Context.runLoop(IteratorBlock.java:148) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.Environment.visitIteratorBlock(Environment.java:559) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.IteratorBlock.accept(IteratorBlock.java:67) > [freemarker-2.3.22.jar:2.3.22] > at freemarker.core.Environment.visit(Environment.java:312) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.MixedContent.accept(MixedContent.java:62) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.Environment.visitByHiddingParent(Environment.java:333) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.ConditionalBlock.accept(ConditionalBlock.java:48) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.Environment.visitByHiddingParent(Environment.java:333) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.ConditionalBlock.accept(ConditionalBlock.java:48) > [freemarker-2.3.22.jar:2.3.22] > at freemarker.core.Environment.visit(Environment.java:312) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.MixedContent.accept(MixedContent.java:62) > [freemarker-2.3.22.jar:2.3.22] > at freemarker.core.Environment.visit(Environment.java:312) > [freemarker-2.3.22.jar:2.3.22] > at freemarker.core.EscapeBlock.accept(EscapeBlock.java:48) > [freemarker-2.3.22.jar:2.3.22] > at freemarker.core.Environment.visit(Environment.java:312) > [freemarker-2.3.22.jar:2.3.22] > at > freemarker.core.Environment.process(Environment.java:290) > [freemarker-2.3.22.jar:2.3.22] > at freemarker.template.Template.process(Template.java:312) > [freemarker-2.3.22.jar:2.3.22] > > [2] > > at > freemarker.ext.beans.BeansWrapper.invokeMethod(BeansWrapper.java:1458) > at > freemarker.ext.beans.SimpleMethodModel.exec(SimpleMethodModel.java:71) > at freemarker.core.MethodCall._eval(MethodCall.java:62) > at freemarker.core.Expression.eval(Expression.java:78) > at freemarker.core.ReturnInstruction.accept(ReturnInstruction.java:35) > at freemarker.core.Environment.visit(Environment.java:336) > at freemarker.core.Macro$Context.runMacro(Macro.java:186) > at freemarker.core.Environment.invoke(Environment.java:705) > at freemarker.core.MethodCall._eval(MethodCall.java:74) > at freemarker.core.Expression.eval(Expression.java:78) > at > freemarker.core.Expression.evalAndCoerceToString(Expression.java:82) > at freemarker.core.DollarVariable.accept(DollarVariable.java:41) > at freemarker.core.Environment.visit(Environment.java:336) > at freemarker.core.Environment.visit(Environment.java:341) > at > freemarker.core.Environment.renderElementToString(Environment.java:2200) > at > freemarker.core.StringLiteral.evalAndCoerceToString(StringLiteral.java:96) > at freemarker.core.StringLiteral._eval(StringLiteral.java:73) > at freemarker.core.Expression.eval(Expression.java:78) > at > freemarker.core.Environment.setMacroContextLocalsFromArguments(Environment.java:743) > at freemarker.core.Environment.invoke(Environment.java:693) > at freemarker.core.UnifiedCall.accept(UnifiedCall.java:85) > at freemarker.core.Environment.visit(Environment.java:336) > at freemarker.core.Environment.visit(Environment.java:341) > at freemarker.core.Environment.visit(Environment.java:341) > at freemarker.core.Environment.process(Environment.java:302) > at freemarker.template.Template.process(Template.java:325) -- Thanks, Daniel Dekany
