fixed memory leak caused by compileDebug flag #1951
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Details and code showing the leak: https://github.com/alubbe/memoryleak
In-browser demo: https://alubbe.github.io/memoryleak/
This leak has been bugging me since I updated node from 0.11.13 to 0.11.14. It has affected all my apps and causes them to take up over a gig of ram per process after a few days. Also, the constant GC makes the app slower and slower with each passing hour.
After forcing the processes to restart every day and also seeing the huge performance regression express received in the last Techempower benchmarks, I got fed up enough to go and track down the issue. First, I started to pre-compile the templates during the build step, and eval'ing the files' contents. This completely fixed any issues I had. So I started working on a new express middleware and just as I was about to publish it, I diffed its implementation to jade's own .compile() and found almost no difference.
That's when it hit me - compileDebug is still enabled by default, even in production. Disabling it via
app.locals.compileDebug = false
brought jade's performance to the level of my own implementation. So I scrapped my middleware and started to profile jade with heapdumps when compileDebug is enabled. Weirdly enough, the resulting 500mb process had a heapdump of 3mb. According to v8, everything had been successfully GC'ed. So I embarked on an epic 'comment-out-all-the-things!!!' journey and somehow figured out that the issue is with the object allocation into the jade_debug array, specifically, these kinds of lines:It seems that since node 0.11.13, v8 has forgotten to identify the shared hidden class of the
{lineno: Integer, filename: String}
objects. So I made it explicit by conjuring up a DebugItem and voilà, the memory leak is gone.I'm raising this issue with v8 directly as well (https://code.google.com/p/v8/issues/detail?id=4121), but in the meantime I believe jade should fix it locally because this memory leak exists on node > 0.11.14, 0.12.* and all iojs releases.
I would also like to discuss disabling compileDebug for express' production environment by default, since you already recommend this in the documentation - but that's for a different PR ;)
Looking forward to hear your feedback!