私はメモリを食い続けているため、数ヶ月ごとに手動で再起動する必要がある既存のWindowsサービス(C#で書かれています)をデバッグします。NHibernateを使用したWindowsサービスの使用メモリが増加しています
サービスはあまり複雑ではありません。製品を保持する外部サーバーにjsonファイルを要求します。 次に、このjsonファイルを製品リストに解析します。 これらの製品のそれぞれについて、この製品がすでにデータベースに存在するかどうかを確認しています。存在しない場合は追加されますが、プロパティが更新されます。
このデータベースはPostgreSQLデータベースであり、私たちはORMとしてNHibernate v3.2.0を使用しています。
私はそれを実行したときにサービスをプロファイルするJetBrainsのDotMemoryを使用してきた:
サービスの開始をし、30代の後にそれがその仕事をして開始します。 SnapShot#1は、最初の実行前に作成されます。 スナップショット#6は、5回目の実行後に作成されました。 他のスナップショットは実行後にも作成されます。 それぞれの実行後にわかるように、オブジェクトの数は約1秒で増加します。毎回実行後に数MBのメモリが使用されます。近いスナップショット#6で探し
、保持サイズはほとんどがNHibernateのセッションオブジェクトによって使用されて示しています
ここに私の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.BeginSession
とbase.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
を持っています。
あなたの 'DoServiceWork'はシングルトンですか? SAPProductProcessorが毎回作成されるのがわかります。おそらくそれは見るべき何かですか? –
SessionFactoryはプロパティですか? SessionFactoryはどこに作成されますか?プロセス(またはAppDomain)に対して1回のみ作成する必要があります。 –
比較を開き、すべての新しいオブジェクトを開き、保持されているオブジェクトとその理由を調べます。 –