Spring's Web MVC - Redirect to the Memory Leak
They say that one rock can cause an avalanche. Lately, one of my
Colleagues, Marcin Radoszewski, gave me such a rock. You'll probably
never guess what it is, but there is a chance, that you use it in many
of your Web Applications. Allow me to introduce this rock to you :)
You probably well know redirect after post pattern. Using Spring Framework you have few ways to implement it, let's focus on one of them, returning the target URL as the String with redirect: prefix.
Suppose that we have controller using this method of redirecting, and we
have to pass some parameters during the redirect, let it be some entity
ID for example:
@RequestMapping(method = RequestMethod.POST)
public String onPost(...) {
...
return "redirect:form.html?entityId=" + entityId;
}
As you see, our rock doesn't look dangerous, it even doesn't look
suspicious :) - What the heck is wrong with that?! - you may ask. Well,
to explain that, we have to take a look at the way how Spring Framework handles the value returned by you.You may start from reading Resolving views in Spring Framework documentation, and then take a closer look at the source code of AbstractCachingViewResolver, which is base class for many different View Resolvers in Spring, including: JSP, FreeMarker, Velocity, Jasper Reports, Tiles and XSLT view resolvers.
When resolveViewName method is called on AbstractCachingViewResolver it uses HashMap based view cache to speed up view resolving in the future calls, and cache key is by default created using view name and current locale.
Now to the clue :) - when you use the above method of redirecting, Spring Framework uses the whole String returned from your controller's method as the view name, including all parameters included in the target URL. Each time you perform the redirect, the parameters may vary, thus such a redirect will leave one additional entry in view cache of AbstractCachingViewResolver, causing memory leak.
How soon that will kill my application? - you may ask. That depends on the amount of memory assigned to JVM, and the number of performed redirects :) - I've made some tests using: -Xmx64M option, with simple application build from only one controller - see this example. After about 76400 redirects the application died with OutOfMemoryError: Java heap space.
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)






Comments
Harald Wellmann replied on Mon, 2012/12/10 - 11:45am
Looks like a bug in Spring. Did you or your colleague file an issue?
joshua long replied on Tue, 2012/12/11 - 12:49pm
Hi - please see this JIRA for ways to avoid this particular behavior. The caching works as expected, and there are ways to not incur the error, or disable caching all together.
Michal Jastak replied on Thu, 2012/12/13 - 1:20am
in response to:
Harald Wellmann
Yes, I did - AbstractCachingViewResolver - caching redirect views leads to memory leak - Joshua Long has mentioned it above.
Michal Jastak replied on Thu, 2012/12/13 - 1:28am
in response to:
joshua long
Regardless of other possible redirect methods (see comment made by Rossen in JIRA), which I agree are a way better than presented by me, using HashMap for caching without any size restriction is just asking for troubles :(
If memory leak is expected cache behavior, then Spring Framework guys wouldn't correct it ;)