Monday, August 26, 2013

My Story on Java Memory Leak

Weeks ago I got an email saying that someone investigated our application (well, the application is neither initially designed nor implemented by me to be precise). Apparently he was hired by our client to find problems and give advice on how to increase application's performances. One of his findings that was sent to me to analyse was a memory leak report. I didn't have an idea on how Java can create memory leak. I understand that we have to destroy an object and release its memory, only if we, our self, allocate memory as in C. Turned out, there are many ways to create memory leak in Java through inappropriate use of design and code. These are the reports that were sent to me.




Having little knowledge of this application's design now I need to find the root cause of this? Great. The report shows that the top three memory consumers are Hibernate SessionFactoryImpl so it must be something to do with Hibernate. My first step was I need to be able to reproduce the report, see if it happens on my local machine (hoping that it only happens on production machine so I can blame the production environment :p). The report was generated using Eclipse Memory Analyser Tool (MAT), so I run it and boom the MAT produced completely same report. Interestingly, the memory leak happens even after the application was deployed on Weblogic App Server.

First, I thought the session was not properly closed. But looking at the code, it uses getCurrentSession() method provided by Hibernate and then by reading at Hibernate document I knew that it is maintained by Hibernate, developers are not allowed to close it manually.

So then how about Hibernate configuration? I changed the configuration a bit here and there.

<prop key="hibernate.connection.release_mode">after_statement</prop>
The connection must be released immediately after a statement is run.

<prop key="hibernate.cache.use_query_cache">false</prop>
I disabled the query cache.

<prop key="hibernate.transaction.flush_before_completion">true</prop>
Each transaction is flushed immediately.

<prop key="hibernate.transaction.auto_close_session">true</prop>
Each session is closed automatically.

But none of them cure the problem. Until then I realized that the SessionFactoryImpl was loaded because Hibernate check named query at startup. So I set this startup_check to false.

<prop key="hibernate.query.startup_check">false</prop>

Then the report shows the actual culprit. The root cause is our ApplicationContextLoader.




The configuration is loaded statically when the class is loaded by using static block. Moreover, it is set to a static variable which means it stays forever until the ApplicationContextLoader class is unloaded from memory.
 

©2009 Stay the Same | by TNB