2

我正在使用 Fluent NHibernate 作为我们的 ORM,但出现内存泄漏错误。

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

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

  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 类继承了我的所有控制器。通过这个,我得到了每次操作命中的“_repository”对象。

我的会话管理逻辑

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();
    }    
 }

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

这就是我如何使我的网站流动起来。请您查看此代码并告诉我为什么会收到此错误。

提前谢谢你。

4

1 回答 1

1

问题:

  • 你基本上每个实体都举行一个会话,永远打开。然而 ISession 实现了工作单元模式,这并不意味着这个。
  • CheckAndOpenSession()不是线程安全的,但 web 服务本质上是线程的:每个请求通常都有自己的线程。
  • 什么用途

每个业务操作都应该有自己的会话,该会话在结束时被处理掉。业务操作通常是控制器操作或 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();
}
于 2013-03-12T13:25:29.227 回答