流畅的NHibernate中的内存泄漏

时间:2013-03-09 13:52:09

标签: c# .net asp.net-mvc fluent-nhibernate

我使用Fluent NHibernate作为我们的ORM,我收到了内存泄漏错误。

我在任务管理器中观察过,每当我尝试从同一台PC中的不同网页浏览器访问主页时,CPU使用率为2-3%,但内存使用率为80-90%,这会导致网站速度变慢并导致系统挂起。 要再次运行我的webisite,我必须从任务管理器结束该过程。还有一件事,当我从浏览器访问它时它会使用一些内存,但当我关闭它时,它不释放所有资源(该内存)。

我以这种方式制作了我的网站的架构: -

  1. 我创建了一个“ParentObject”类,其中我创建了Repository对象作为静态成员。
  2. 我创建的所有实体都是从“ParentObject”类继承的。
  3. 我又创建了一个类BaseController,它继承自“Controller”类,在Base类中我使用了这段代码: -

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
       base.OnActionExecuting(filterContext);
       EdustructRepository Repository;  // My Repository Class where I have written logic for opening and closing Save and Update Session.I have mentioned my this logic below
        if (Session["Repository"] != null)
        {
            Repository = (EdustructRepository)Session["Repository"];
            if (!Repository.GetSession().Transaction.IsActive)
               Repository.GetSession().Clear();
        }
        else
        {
            Repository = new EdustructRepository(typeof(ActivityType), FluentNhibernateRepository.DataBaseTypes.MySql);
            Session["Repository"] = Repository;
        }
        if (ParentObject._repository == null)   
        {
            ParentObject._repository = new EdustructRepository();  // Here i have set the ParentObject's static variable "_repository" by this i have accessed repository in all my Entities .
        }
    }
    
  4. 我用BaseController Class继承了我的所有控制器。通过这个,我得到了每个Action命中的“_repository”对象。

  5. 我的会话管理逻辑

    public class EdustructRepository : NHibernetRepository
    {
    
        public void Save<T>(T item, bool clearSession)
        {
            if (typeof(T).GetProperty("Created_at").GetValue(item, null).ToString() == DateTime.MinValue.ToString())
            {
                typeof(T).GetProperty("Created_at").SetValue(item, MySqlDateTime.CurrentDateTime(), null);
            }
            typeof(T).GetProperty("Updated_at").SetValue(item, MySqlDateTime.CurrentDateTime(), null);
            base.CheckAndOpenSession();
            using (var transaction = base.GetSession().BeginTransaction())
            {
                try
                {
                    base.GetSession().SaveOrUpdate(item);
                    transaction.Commit();
                    if (clearSession)
                    {
                        Session.Clear();
                    }
                }
                catch
                {
                    base.Evict(item);
                    base.Clear();
                    throw;
                }
            }
            //base.Save<T>(item, clearSession);
        }
    
        public void Save<T>(T item)
        {
            Save<T>(item, false);
        }
    }
    
    public class NHibernetRepository : IDisposable
    {
        public static ISessionFactory _SessionFactory = null;
    
        protected ISession Session = null;
    
        private ISessionFactory CreateSessionFactory()
        {
            return Fluently.Configure()
              .Database(MySQLConfiguration.Standard.ConnectionString(c => c.FromConnectionStringWithKey("DBConnectionString")))
              .Mappings(m =>m.FluentMappings.AddFromAssembly((Assembly.Load("Edustruct.Social.DataModel"))).Conventions.Add<CascadeConvention>())
              .ExposeConfiguration(cfg => cfg.SetProperty(NHibernate.Cfg.Environment.CurrentSessionContextClass,"web"))
              .BuildSessionFactory();
        }
    
        protected void CheckAndOpenSession()
        {
            if (_SessionFactory == null)
            {
                _SessionFactory = CreateSessionFactory();
            }
            if (Session == null)
            {
                Session = _SessionFactory.OpenSession();
                Session.FlushMode = FlushMode.Auto;
            }
            if (!Session.IsOpen)
                Session = _SessionFactory.OpenSession();
            else if (!Session.IsConnected)
                Session.Reconnect();
        }    
     }
    

    注意:我们没有在我们的存储库中关闭Session,因为我正在使用延迟初始化,我也在View中使用它,所以如果我在这里关闭会话,我会收到显示“找不到会话”的错误。

    这就是我的网站流量。 请您查看此代码并告诉我为什么会收到此错误。

    提前感谢你。

1 个答案:

答案 0 :(得分:1)

问题:

  • 你基本上每个实体持有一个会话永远开放。然而,ISession实现了工作模式,而不是为此。
  • CheckAndOpenSession()不是线程安全的,但是webserving本质上是线程化的:每个请求通常都有自己的线程。
  • 什么是使用

每个业务操作都应该有自己的会话,并在会话结束时进行处理。业务操作通常是控制器操作或Web方法。

样品

// on appstart
GlobalSessionFactory = CreateSessionFactory();


// in basecontroller befor action
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
   base.OnActionExecuting(filterContext);
   DatabaseSession = GlobalSessionFactory.OpenSession();
}

// in basecontroller after action (pseudocode)
protected override void OnActionExecuted()
{
    DatabaseSession.Dispose();
}