PDA

View Full Version : Memory Leak (kind of) in HibernateTemplate



sreenivask
05-13-2007, 06:57 PM
Mark:

We have used Spring's HibernateTemplate services to develop the DAO layer of a large business application. The Services/persistence layer has around 800K lines of C# code. There are aproxmiately 1100 DAO classes (each inheriting from HibernateDaoSupport) in this layer.

Due to issues of change management that we could not solve, we decided not to use DI. And, we ended up hardwiring the DAOs to the Service Layer. :(

Each service call, therefore, results in the creation of a new DAO object. And--here is crux of the problem--each DAO object creates a ProxyFactory for the Session object that Execute and ExecuteFind pass as a parameter to Anonymous Delegates).

Normal testing--10 testers concurrently testing different services--creates a load of around 10-20 business transactions per minute. That is, around 60 calls to the DAOs resulting in the creation of 60 ProxyFactories per minute and these never get garbage collected. Using WinDbg we found that 95% of the GC heap is occupied by these ProxyFactories.

We set HibernateTemplate.ExposeNativeSession = true as a temporary fix. This stopped the growth of the heap, but will make the solution vulnerable to bugs caused by inadvertent closure of the session within the delegates.

What would be a more permanent fix?


Even if we were to use DI to inject the DAO (singleton) into the Services layer, it would still result in the creation of 1100 proxyfactories (one for each DAO) for the session object, since CreateSessionProxy() is unaware of ProxyFactories created by other instances of HibernateTemplate. How can we make HibernateTemplate.CreateSessionProxy() be aware of the other ProxyFactories?

Can we change the visibility of "HibernateTemplate.sessionProxyFactory" to public and use DI to inject the proxyfactory into HibernateTemplate in each DAO?

Sreenivas K.

Mark Pollack
05-14-2007, 04:03 PM
Hi Sreenivas,

If you can have your service and dao layer objects be singletons then the overhead of creating them is fixed and presumebly an acceptable level. That would be the best short term fix without any code changes. Sharing a proxyfactory instance is a good suggestion, though I'd like the default settings of the template to be robust so that users don't have to worry about these details. Let me ping the other spring.net developers for ideas, maybe thread local storage or a dedicated typebuilder. Another fix would to to not use the dynamic proxy in the template at all and instead create a 'traditional proxy', i.e. just a plain ol' C# decorator class, that would allow it to be GC'd.

As an aside, for the generic version of HibernateTemplate, I'll add the method 'CreateSessionProxy', so that it can be overriden by subclasses since right now it directly delegates to the non generic template implemetation. There might be other cases likes this. I'll rethink the strategy of wrapping the non-generic template and/or allow an alternate implementation of the non generic INHiberateOperations to be specified in the generic version.

Cheers,
Mark

Mark Pollack
05-14-2007, 08:42 PM
Hi,
I believe we can fix this by introducing some caching for the generated types... . Just wanted to keep you posted.
Cheers,
Mark

Mark Pollack
05-16-2007, 03:15 PM
Hi Sreenivas,

I'll be fixing this today by creating declaring and configuring a static ProxyFactory in the template. The setting of the new target and creating an instance of the type will be done in a thread safe manner inside the CreateProxy method, which I'll add to the generic version of the template so that subclasses could modify the default behavior. I'll post back once it is all commited, I'm sorting out some unrelated build issues to ensure you get the latest spring.data etc in the download. Caching strategies the generated types is an optimization for other use-cases, not this one where one proxyfactory will do, as you correctly pointed out in your original email.

Cheers,
Mark

Mark Pollack
05-23-2007, 06:18 AM
Hi,

I've gone with your original suggestion. I experimented with some more lower level caching of the proxy types but it requires more extensive testing. In short, I've added a ProxyFactory property to HibernateTemplate, so you can set it once and the same instance (assuming of course singleton=true) will shared by all instances of your classes that inherit from HibernateDaoSupport. You must set the instance of HibernateTemplate property on HibernateDaoSupport as well. Sorry for the added configuration inconvenience for your case.

Cheers,
Mark

sreenivask
05-27-2007, 03:29 AM
Hi Mark,

Thanks for the fix. Right now our solution is going through the acceptance test cycle. Planning to use the fix in June. Will let you know if there are any problems.

I am curious to know the reasons for not taking the static property (for ProxyFactory) route.

Regards,
Sreenivas

Mark Pollack
05-27-2007, 05:56 PM
Hi,
I was leary of introducing a static member, I like to avoid them if at all possible. I may go back to that in the future as the default option, with the property overriding the use of static.
Cheers,
Mark

sreenivask
06-11-2007, 05:44 PM
Hi Mark,

We rescheduled the testing of the fix you provided for June 3rd week.

Meanwhile, on June 5, I had seen a commit related to AOP proxy type cache (SPRNET-528 (http://opensource.atlassian.com/projects/spring/browse/SPRNET-528)). Do you think it can be of any use here?

Bruno Baia
06-12-2007, 11:06 AM
We added an Aop proxy type cache, but it's not activated for now, we wanted to do some tests before.

Erich pointed out some thread safe problem caching the ProxyFactory, and this solution requires extra configuration, so maybe you can try the Aop proxy type cache.
To activate it, you need to change Spring.Aop.Framework.ProxyConfig class :
Replace


private IAopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();

By


private IAopProxyFactory aopProxyFactory = new CachedAopProxyFactory();



Let us know if you try it,
Bruno

Mark Pollack
07-16-2007, 06:54 PM
Hi,
FYI, the aop cache is active now in M2. Pending futher testing, we will remove the ProxyFactory configuration on HibernateTemplate. Thanks for your patience.
Cheers,
Mark