2017-11-15 4 views
0

私はメモリを食い続けているため、数ヶ月ごとに手動で再起動する必要がある既存のWindowsサービス(C#で書かれています)をデバッグします。NHibernateを使用したWindowsサービスの使用メモリが増加しています

サービスはあまり複雑ではありません。製品を保持する外部サーバーにjsonファイルを要求します。 次に、このjsonファイルを製品リストに解析します。 これらの製品のそれぞれについて、この製品がすでにデータベースに存在するかどうかを確認しています。存在しない場合は追加されますが、プロパティが更新されます。

このデータベースはPostgreSQLデータベースであり、私たちはORMとしてNHibernate v3.2.0を使用しています。

私はそれを実行したときにサービスをプロファイルするJetBrainsのDotMemoryを使用してきた: DotMemory overvies

サービスの開始をし、30代の後にそれがその仕事をして開始します。 SnapShot#1は、最初の実行前に作成されます。 スナップショット#6は、5回目の実行後に作成されました。 他のスナップショットは実行後にも作成されます。 それぞれの実行後にわかるように、オブジェクトの数は約1秒で増加します。毎回実行後に数MBのメモリが使用されます。近いスナップショット#6で探し

、保持サイズはほとんどがNHibernateのセッションオブジェクトによって使用されて示しています

Snapshot #6

ここに私のOnStartコードです:

try 
{ 
    // Trying to fix certificate errors: 
    ServicePointManager.ServerCertificateValidationCallback += delegate 
    { 
     _logger.Debug("Cert validation work around"); 
     return true; 
    }; 

    _timer = new Timer(_interval) 
    { 
     AutoReset = false // makes it fire only once, restart when work is done to prevent multiple runs 
    }; 
    _timer.Elapsed += DoServiceWork; 
    _timer.Start(); 
} 
catch (Exception ex) 
{ 
    _logger.Error("Exception in OnStart: " + ex.Message, ex); 
} 

そして、私のDoServiceWork:

try 
{ 
    // Call execute 
    var processor = new SAPProductProcessor(); 
    processor.Execute(); 
} 
catch (Exception ex) 
{ 
    _logger.Error("Error in DoServiceWork", ex); 
} 
finally 
{ 
    // Next round: 
    _timer.Start(); 
} 

SAPProductProcessorでは2回のdb呼び出し。どちらもループしています。 JSONファイルからのすべての製品を通じて Iループおよび製品は、製品のコード使用して、テーブルにすでに存在するかどうかを確認:

ProductDto dto; 
using (var session = SessionFactory.OpenSession()) 
{ 
    using (var transaction = session.BeginTransaction(IsolationLevel.ReadCommitted)) 
    { 
     var criteria = session.CreateCriteria<ProductDto>(); 
     criteria.Add(Restrictions.Eq("Code", code)); 
     dto = criteria.UniqueResult<ProductDto>(); 
     transaction.Commit(); 
    } 
} 
return dto; 

をそしてproductDtoが更新されたときに私が使用してそれを保存します。

using (var session = SessionFactory.OpenSession()) 
{ 
    using (var transaction = session.BeginTransaction(IsolationLevel.ReadCommitted)) 
    { 
     session.SaveOrUpdate(item); 
     transaction.Commit(); 
    } 
} 

を私はメモリとオブジェクトの数を増やすことを止めるために上記のコードをどのように変更するのかよくわかりません。

すでにusing (var session = SessionFactory.OpenSession())の代わりにvar session = SessionFactory.GetCurrentSession();を使用してみましたが、メモリの増加を止めませんでした。私のデータアクセスクラスMultiSessionFactoryProvider sessionFactoryProviderのコンストラクタで

更新が注入されます。そして、基底クラスは: base(sessionFactoryProvider.GetFactory("data"))で呼び出されます。私は、最後に開始時base.BeginSessionbase.EndSessionを呼び出して、私のデータアクセスクラスでは

ISession session = ThreadLocalSessionContext.Unbind(_sessionFactory); 
if (session != null) 
{ 
    session.Close(); 
} 

ISession session = _sessionFactory.GetCurrentSession(); 
if (session == null) 
{ 
    session = _sessionFactory.OpenSession(); 
    ThreadLocalSessionContext.Bind(session); 
} 

そしてEndSession:この基本クラスはメソッドBeginSessionを持っています。

+0

あなたの 'DoServiceWork'はシングルトンですか? SAPProductProcessorが毎回作成されるのがわかります。おそらくそれは見るべき何かですか? –

+2

SessionFactoryはプロパティですか? SessionFactoryはどこに作成されますか?プロセス(またはAppDomain)に対して1回のみ作成する必要があります。 –

+0

比較を開き、すべての新しいオブジェクトを開き、保持されているオブジェクトとその理由を調べます。 –

答えて

0

シングルトンについての提案は私のデータアクセスクラスを詳しく見てくれました。

私はすべての実行でこのクラスを作成すると、範囲外で実行されたときにNHibernateメモリを解放すると考えました。私はクラスのデストラクタでいくつかのdispose呼び出しを追加しました。しかし、それは動作しませんでした、または私は正しくそれをやっていない可能性があります。 データアクセスクラスを静的フィールドに保存して再利用するようになりました。今では私の記憶はそれ以上は増えず、もっと重要なのは、開いているオブジェクトの数が変わらないということです。私はちょうどDotMemoryを使って1時間以上実行して150回実行し、最後のスナップショットのメモリはまだ約105MBであり、オブジェクトの数はまだ117kで、私のSessionFactory辞書は150MBでなく4MBになりました。 。

関連する問題