-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: Memory leakage like symptom
PostPosted: Sun Feb 17, 2008 8:40 am 
Newbie

Joined: Sun Jun 10, 2007 5:32 pm
Posts: 8
Location: Gothenburg
Hi!

I recently ran into a memory leakage like problem when using NHibernate in a windows service. My guess is that the SessionFactory is not releasing some resources under certain circumstances. I've written some code to reproduce the problem. When running this testapp as a console application, the problem does not appear, when running it as a nunit test, it does. A mystery for me...

NHibernateMemoryLeakage.MemoryLeakage() opens a session, gets a customer object from the Northwind database and disposes of the session. It does this a thousand times. The result from GC.GetTotalMemory(true) keeps growing.

NHibernateMemoryLeakage.MemoryLeakageDisposeSessionFactory() does the same thing, but also disposes of SessionFactory each iteration. The result from GC.GetTotalMemory(true) does not keep growing.

The memory leakage problem in my windows service disappearad when I also disposed of the SessionFactory whenever disposing of a Session.

My system configuration for this test:
.NET2.0 (version 2.0.50727.42)
Windows XP SP2
NHibernate 1.2.0.4000 (Build 1.2.0.GA)
NUnit 2.2.9.0

App.config:
Code:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section
        name="hibernate-configuration"
        type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"
        />
  </configSections>

  <system.diagnostics>
    <trace autoflush="true">
      <listeners>
        <add name="console" type="System.Diagnostics.ConsoleTraceListener" />
      </listeners>
    </trace>
  </system.diagnostics>

  <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <session-factory>
      <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
      <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
      <property name="connection.connection_string">Data Source=(local);Initial Catalog=Northwind;Integrated Security=True</property>
      <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
      <mapping assembly="NHibernateMemoryLeakage"/>
    </session-factory>
  </hibernate-configuration>
</configuration>


Customer.cs
Code:
using System;

namespace NHibernateMemoryLeakage
{
    public class Customer
    {
        private string id;

        public virtual string Id
        {
            get { return id; }
            set { id = value; }
        }

        private string companyName;

        public virtual string CompanyName
        {
            get { return companyName; }
            set { companyName = value; }
        }

        private string contactName;

        public virtual string ContactName
        {
            get { return contactName; }
            set { contactName = value; }
        }

        private string contactTitle;

        public virtual string ContactTitle
        {
            get { return contactTitle; }
            set { contactTitle = value; }
        }

        private string address;

        public virtual string Address
        {
            get { return address; }
            set { address = value; }
        }

        private string city;

        public virtual string City
        {
            get { return city; }
            set { city = value; }
        }

        private string region;

        public virtual string Region
        {
            get { return region; }
            set { region = value; }
        }

        private string postalCode;

        public virtual string PostalCode
        {
            get { return postalCode; }
            set { postalCode = value; }
        }

        private string country;

        public virtual string Country
        {
            get { return country; }
            set { country = value; }
        }

        private string phone;

        public virtual string Phone
        {
            get { return phone; }
            set { phone = value; }
        }

        private string fax;

        public virtual string Fax
        {
            get { return fax; }
            set { fax = value; }
        }
    }
}


Customer.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateMemoryLeakage" namespace="NHibernateMemoryLeakage">
  <class name="Customer" table="Customers" lazy="true">
    <id column="CustomerID" name="Id">
      <generator class="assigned" />
    </id>

    <property name="CompanyName" not-null="true" />
    <property name="ContactName" not-null="false" />
    <property name="ContactTitle" not-null="false" />
    <property name="Address" not-null="false" />
    <property name="City" not-null="false" />
    <property name="Region" not-null="false" />
    <property name="PostalCode" not-null="false" />
    <property name="Country" not-null="false" />
    <property name="Phone" not-null="false" />
    <property name="Fax" not-null="false" />
  </class>
</hibernate-mapping>


NHibernateTest.cs:
Code:
using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using System.Diagnostics;

namespace NHibernateMemoryLeakage
{
    [TestFixture]
    public class NHibernateTest
    {
        private long lastPrivateMemory;

        static void Main(string[] args)
        {
            new NHibernateTest().MemoryLeakage();
        }

        [Test]
        public void MemoryLeakage()
        {
            lastPrivateMemory = 0;

            for (int i = 0; i < 1000; i++)
                getCustomer();
        }

        [Test]
        public void MemoryLeakageDisposeSessionFactory()
        {
            lastPrivateMemory = 0;

            for (int i = 0; i < 1000; i++)
            {
                getCustomer();

                sessionFactory.Dispose();
                sessionFactory = null;
            }
        }

        private void getCustomer()
        {
            using (NHibernate.ISession session = SessionFactory.OpenSession())
            {
                Customer customer = session.Get<Customer>("ALFKI");
                long currentPrivateMemory = GC.GetTotalMemory(true);
                long diff = currentPrivateMemory - lastPrivateMemory;
                Trace.WriteLine(String.Format("Current: {0}, Diff: {1}", currentPrivateMemory, diff));
                lastPrivateMemory = currentPrivateMemory;
            }
        }

        private NHibernate.ISessionFactory sessionFactory = null;

        public NHibernate.ISessionFactory SessionFactory
        {
            get
            {
                if (sessionFactory == null)
                    sessionFactory = new NHibernate.Cfg.Configuration().Configure().BuildSessionFactory();
                return sessionFactory;
            }
        }
    }
}


Thanks,

Peter Albertsson


Top
 Profile  
 
 Post subject: Memory leakage like symptom
PostPosted: Tue Mar 11, 2008 8:55 am 
Newbie

Joined: Mon Jul 16, 2007 2:25 am
Posts: 7
Hi Peter

I have also noticed this. Our application is also using a windows service that caches the session factory. The documentation recommends caching the session factory because creating a factory is a time consuming operation as the mapping files need to be loaded.

What is interesting this appears to be a standard practice for ASP.Net applications. You would have thought the leak would have been noticed by others?

How has the performance been since you started disposing the session factory?

I have post title NHibernate and Memory usage which shows a dump of GVC Gen 2 that contains references to NHibernate SQLCommand class

Cheers
Peter Karouzos


Top
 Profile  
 
 Post subject: Re: Memory leakage like symptom
PostPosted: Tue Mar 18, 2008 3:10 pm 
Newbie

Joined: Sun Jun 10, 2007 5:32 pm
Posts: 8
Location: Gothenburg
Quote:
What is interesting this appears to be a standard practice for ASP.Net applications. You would have thought the leak would have been noticed by others?


I have other applications, e.g. a webservice hosted by IIS, and I haven't seen this problem there. I haven't invested this thoroughly, but my impression is that this problem only occurs in a windows service and under NUnit tests.

Quote:
How has the performance been since you started disposing the session factory?


It takes a long time to initialize the session factory, but high performance was not an issue in this application.

Quote:
I have post title NHibernate and Memory usage which shows a dump of GVC Gen 2 that contains references to NHibernate SQLCommand class


Thanks, I will subscribe to that thread, hoping for a talented person to find a solution.


Top
 Profile  
 
 Post subject: Memory Leak when using SysCache
PostPosted: Wed Apr 02, 2008 5:58 am 
Beginner
Beginner

Joined: Wed Nov 29, 2006 10:32 am
Posts: 34
We are quite sure that there is a real memory leak in SysCache (we still use NHib 1.2.0). The leak comes from the fact that the SysCache enters a special root object in its System.Web.Caching.Cache, which also gets a callback called RootCacheItemRemoved, which in turn is registered somewhere as System.Threading._TimerCallback (dotTrace shows us these connections).

Unfortunately, the Destroy/Clear methods of the SysCache are implemented as follows:

Code:
         RemoveRootCacheKey();
         StoreRootCacheKey();


which means that the callback will exist for ever and be attached to the (static) Timer; and because the callback is an object function (not a static one), it remembers the this pointer, i.e. the SysCache itself. In addition, the global/singleton key for that root object in the Web...Cache is a new Guid, so there is no chance to overwrite the cache entry - new entries are created on and on.

So, having multiple SessionFactory objects will leak memory. We do have problems e.g. with test runs in NUnit, where each unit test creates a new SessionFactory - after a few hundred test runs, memory is exhausted :-(

As we see it, the only possibility (when using SysCache) is to repair the code above, i.e. not call StoreRootCacheKey() in Clear(), but only lazily - which, interestingly, anyway is done in Put()! So maybe removing the second line above solves the problem ...

If someone knows anything about this, please let it be known - we will try it ourselves.

Regards
Harald & Markus


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
cron
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.