4

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!

Leo
  • 187
  • 6
  • 19
  • 6
    This code misses the entire point of an IoC container. You don't **pull** beans from the factory, you let it **push** the beans into your bean! – Marko Topolnik May 07 '12 at 11:27
  • Although it may give the impression that I am pulling the beans, I am actually not hardcoding the bean name in the code. I am using a common property file, using which, Spring actually pushes the beans. – Leo May 07 '12 at 11:59
  • 2
    This sounds even worse. Bean name should be in the xml configuration file and your Java code shouldn't even know that the IoC container exists, let alone the configured name of any bean. – Marko Topolnik May 07 '12 at 12:03
  • I think I get your point. So you mean to say, no matter what, doing BeanFactory.getBeans("beanName") should be avoided? But I wonder, even in this case the implementation of the bean is unknown to the calling class and only Spring will know which bean class is to be injected at runtime. Am I missing anything? – Leo May 08 '12 at 07:46
  • Yes, that's it. You get the same end result that you have now, but with zero code on your part (except if you count the xml config as code). – Marko Topolnik May 08 '12 at 07:54

2 Answers2

4

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.

gigadot
  • 8,879
  • 7
  • 35
  • 51
  • Thanks. I just updated my question. I am getting java.lang.OutOfMemoryError: Java heap space. And 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. – Leo May 14 '12 at 08:48
  • 1
    Does it have anything to do with threading in your code? if so, http://stackoverflow.com/questions/1071631/trying-to-track-down-a-memory-leak-garbage-collection-problem-in-java – gigadot May 15 '12 at 11:57
  • Thanks. The link helped in getting further understanding about the issue. However, I have tried calling getHibernateTemplate.flush() and .clear() It does not seem to help though. – Leo May 22 '12 at 10:14
  • I believe that there is a session set per hibernate class. so if the hibernate classes do not get unloaded (according to the reason i gave in the answer), their session will not get garbage collected too since they are still associated with the classes in permanent generation. Try to use the options i suggested above and let me know what happens. – gigadot May 22 '12 at 13:47
  • Yes the issue is related to sessions. But not to class loading I suppose. I had tried using the JVM options you suggested but they didnt help. What helped though is explicitly closing the session through "getHibernateTemplate().getSessionFactory().close()" (see update). Seems like spring is not closing the session! – Leo May 23 '12 at 14:38
  • That is odd. If the container is garbage collected the session should be too. The only reason I could think of is that they are associated with other thread. Anyway, as long as you solve the problem that's good enough. – gigadot May 23 '12 at 14:58
  • The first thought that came to me too was that the issue has to do with multiple threads. But I was left clueless when the issue persisted even when I ran it in a single thread! Spring's HibernateTemplate having some problem is all I can think of right now. – Leo May 23 '12 at 15:56
  • I looked into the Spring and Hibernate related classes, some of them have Map of Threads so it might be done internally and you probably cannot control it to a single Thread as you said. – gigadot May 23 '12 at 21:51
  • Running it in a single thread means making the application single threaded from my implementation perspective. I should not care whether internally Spring/Hibernate uses single or multi threading (one of the core cocepts of OOP!). This is provided Spring HibernateTemplate framework itself is robust. – Leo May 24 '12 at 07:27
  • I understood that. I only mean what you cannot control may be the cause of your problem. – gigadot May 24 '12 at 09:12
1
  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.

Spencer Kormos
  • 8,381
  • 3
  • 28
  • 45
  • Thanks Spencer. For(1), I am not explicitly registering the container anywhere. Any pointers on the common instances where Spring containers could be automatically registered? For(2), the beans I have made prototype are DAO beans and using them as singleton may create conflicts for different users. – Leo May 08 '12 at 07:50