Reputation: 187
I am using Spring framework (ver 3.0.3) in my application. Lately, I was getting this nasty java.lang.OutOfMemoryError: Java heap space
error. The error did not come immediately upon execution but after a few hours of the application running. Until that point, the application would run perfectly fine and then all of a sudden the jvm would crash giving out of memory error.
Upon extensive investigation, I figured that the issue had something to do with Spring. I noticed that all classes, whenever they needed a bean to be injected, they created a new instance of XMLBeanFactory. That is, they all had this code at the start:
XmlBeanFactory beanfactory = new XmlBeanFactory(new ClassPathResource("SpringConfig.xml"));
Bean myBean = beanfactory.getBean("MyBean");
I understand that this is not recommended. You need only one instance of Spring container and refer to that instance for all bean creation requests. So I implemented a SpringFactory through a singleton, thereby creating single instance of XMLBeanFactory always.
Making the above change seems to have solved the memory leak issue!
I am not yet able to make up my mind on:
Update:
I came up with interesting findings, after I added the following piece of code to all my Spring beans:
protected void finalize()
{
System.out.println(this +" object is garbage collected");
}
I ran the code by having each class instantiate a new Spring container and then get the bean.The above comment was printed for almost all beans created. This means that all the Spring beans are getting cleaned up. However, the used up memory went on increasing with time.
When I did the same thing by having all classes use same Spring container, used memory remained more or less stable. This makes me think that Spring containers are holding memory.
So question is, when is a Spring container(obtained as in above code) garbage collected? I thought it would be eligible for garbage collection once it goes out of scope!!
It seems that Hibernate Session Object is caching resources and holding up memory. I am not sure about this but heap dump analysis shows Hibernate 'strings' as major memory holders, eg. some strings had sql queries and hibernate created aliases. But I wonder how and why Hibernate caching (I am not using second level cache) would cause the issue only when I use multiple Spring containers!
Update:
Finally I was able to pin point what is holding up memory. It is the primary cache generated by Hibernate. The objects got cleared as we have getHibernateTemplate().clear()
. However, the sql queries and hibernate properties are getting cached for every session and a new session is created by each spring container. As the cache should get cleared automatically when the session is closed, the memory growth implies that the session is not getting closed. This is further verified as I got no memory issues when I explicitly did getHibernateTemplate().getSessionFactory().close()
at the end of my DAO class.
So, the concern is, why is spring hibernate template not closing the session even when the container itself is going out of scope? I am not handling the session explicitly anywhere in the code and the issue persists even if I have a single thread running. Makes me feel like something is wrong with the framework implementation itself!
Upvotes: 4
Views: 10224
Reputation: 8969
Which OutOfMemoryError did you get exactly? I reckon it is java.lang.OutOfMemoryError: PermGen space
If so, here is the explanation:
Each spring container uses a different class loader (but they all have the same parent class loader). When a class is loaded, it is put in permanent generation memory, not heap, and they are never garbage collected by JVM by default. The same class that is loaded with a different class loader is considered to be different and, therefore, the permanent generation gets filled up as you create more new Spring IoC and eventually runs out of space giving java.lang.OutOfMemoryError: PermGen space
.
To solve this problem, class unloading option should be enable for your JVM:
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
For other type of out of memory error, I cannot see any explanation at the moment. It is very difficult to create memory leak in Java unless you use thread.
Upvotes: 4
Reputation: 8441
Are your containers really going out of scope, or are they being registered somewhere internally?
The other point of Spring in making your classes stateless is that you have as few instances as possible, and load them up as necessary on start-up. So your scope should be singleton wherever possible, and if not you should be asking yourself why it's not singleton, and can I make it so.
Upvotes: 1