2

ORM として Fluent NHibernate を使用していますが、メモリ リークのエラーが発生します。

同じ PC で異なる Web ブラウザからホームページにアクセスしようとすると、CPU 使用率は 2 ~ 3% ですが、メモリ使用率は 80 ~ 90% になり、Web サイトの速度が低下し、システムがハングします。Web サイトを再度実行するには、タスク マネージャーからプロセスを終了する必要があります。もう1つ、ブラウザからアクセスするとメモリが使用されますが、閉じると、すべてのリソース(そのメモリ)が解放されません。

私はこの方法でウェブサイトのアーキテクチャを作成しました:-

  1. 静的メンバーとしてリポジトリ オブジェクトを作成したクラス「ParentObject」を作成しました。
  2. 私が作成したすべてのエンティティは、「ParentObject」クラスから継承されています。
  3. 「Controller」クラスから継承したもう1つのクラスBaseControllerを作成し、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

問題:

  • 基本的に、エンティティごとに 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 に答える