Leo
Leo

Reputation: 187

Garbage collection of spring container

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:

  1. Even if I use multiple instances of spring containers to get beans, when the container goes out of scope, it should release all bean references making all beans available for garbage collection. What was causing the memory leak issue then? As I mentioned, only using a singleton container has caused the memory leak to vanish. I can provide further details, if required.
  2. The reason why we used multiple containers earlier was because the beans were not stateless. To resolve that issue, in my singleton spring container, I have made all beans scope as prototype. Is this approach correct?

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

Answers (2)

gigadot
gigadot

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

Spencer Kormos
Spencer Kormos

Reputation: 8441

  1. Are your containers really going out of scope, or are they being registered somewhere internally?

  2. 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

Related Questions