handlebars.java icon indicating copy to clipboard operation
handlebars.java copied to clipboard

Freezing and OutOfMemoryError when compiling medium to large sized templates

Open rougou opened this issue 6 years ago • 6 comments

I have a web app where tenants can build their own web pages via drag&drop and other methods (over simplified, but that's the general idea). The pages are put together to form a template and then compiled via handlebars. The compiled templates are cached in the JVM until they are modified or stale, so until now I never worried about the compilation performance so much.

However, I recently found that some tenants have large pages that when compiled either take 20+ seconds, or cause OutOfMemoryError errors that eventually make the entire web app unresponsive.

Here is a sample app I made to demonstrate this issue. I have 3 templates in the resources folder that contain only plain html and no actual template code. litetemplate is around 200KB, mediumtemplate 1MB, and bigtemplate close to 4MB. While litetemplate doesn't exactly compile fast, even mediumtemplate will quickly use several gigabytes of memory and refuse to finish when run in a couple of threads. With bigtemplate even one thread is too much for my PC to handle. In comparison JMustache (commented out but testable in sample) compiles even bigtemplate on several threads in less than a second.

I'm not sure if this is a problem with antlr4 or the particular grammar used, as I'm not too familiar with how antlr works. But there is clearly an issue when the memory usage goes up exponentially for a template without any actual handlebars markup.

Please look into this issue. In the meantime, any workarounds or insight would be greatly appreciated.

[Handlebars version] 4.1.2 (issue first discovered on older 4.0.6 version)

[JDK] AdoptOpenJDK 11

[OS] Windows, Linux

rougou avatar Sep 19 '19 13:09 rougou

@jknack Do you think you will have time to look at this anytime in the near future? I plan to prevent tenants from creating really large pages but am worried about medium sized templates bogging down my application in the long run. Also if you are aware of the issue but couldn't fix due to antlr4 workings or whatever that would also be good to know!

rougou avatar Sep 24 '19 03:09 rougou

Yes, might be related to ANTLR but don't have time to look. Pull request is welcome.

jknack avatar Sep 24 '19 11:09 jknack

The issue starts occurring with the first version using antlr (handlebars 0.10.0). Since I have no guarantees it can be fixed I'm working on adapting the parboiled parser instead. But I don't think it'll be feature complete anytime soon. There are a lot of features I don't need...

rougou avatar Oct 01 '19 01:10 rougou

@jknack Just to update, after comparing Parboiled vs Antlr it seems to be related to the white-space processing. If there are a lot of line breaks, spaces, etc., the antlr version becomes very slow and uses up large amounts of memory. I guess since white-space isn't consumed as TEXT, it'll keep doubling back over the white-spaces until it finds the next "{{", etc. If that is far or non-existent, as in my examples, then we get the extreme processing times and memory usage. If I remove the !isWhite condition below, the problem disappears, but white-space control will break...

  private boolean consumeUntil(final String token) {
    int offset = 0;
    while(!isEOF(offset) && !(ahead("\\" + token, offset) || ahead(token, offset)) &&
      !isWhite(_input.LA(offset + 1))) {

[EDIT] Even with just TEXT tokens, we run out of memory for large files with lots of white-space. So there are simply too many tokens. I'm working on a way to include spaces and newlines in a single TEXT node, to decrease the number of tokens.

rougou avatar Oct 06 '19 15:10 rougou

@jknack I've opened a PR to address this issue. This will greatly improve the performance for templates with a lot of whitespace. The bigtemplate in my sample that was crashing the jvm will now compile in 0 seconds - it'll just be one big text token. Of course that isn't a realistic template and antlr still uses a huge amount of memory per token, but this helps a great deal for web pages, etc.

Please have a look. https://github.com/jknack/handlebars.java/pull/716

rougou avatar Oct 18 '19 14:10 rougou

Thanks, will have a look later (end of the month)

jknack avatar Oct 18 '19 14:10 jknack