NHibernate (バージョン 3.1.0.4000) を使用して [構成に応じて] SQL Server CE (バージョン 3.5) / (MySQL 5.7.11 コミュニティ) データベース テーブルにレコードを書き込むアプリケーションがあります。
データベーステーブルへの保存を行うメソッドは以下のような構造になっているので、正しく破棄する必要があります
using (ISession session = SessionHelper.GetSession())
using (ITransaction txn = session.BeginTransaction())
{
session.Save(entity);
txn.Commit();
}
約 1 週間の重い作業 (数十万のレコードが書き込まれた場所) の後、アプリケーションは動作を停止し、メモリ不足エラーをスローします。
それで:
- SQL Server CE を使用すると、データベースが破損し、手動で修復する必要があります
- MySQL では mysqld デーモンが終了し、再起動する必要があります
ANTS Memory Profiler (SQL CE 構成を使用) を介してアプリケーションのメモリ使用量を監視してきましたが、驚いたことに、アプリケーションの「プライベート バイト」はまったく増加していないようです。これは、ANTS とリソースマネージャー。
それでも、(このようなエラーが表示された後) アプリケーションが強制的に閉じられると、タスク マネージャーの「物理メモリ使用量」が約 80% から 20 ~ 30% に低下し、他のプロセスを再び開始することができます。別のメモリ不足の例外。
いくつかの調査を行ったところ、次のことがわかりました。
プライベート バイト、仮想バイト、ワーキング セットとは何ですか?
プライベート バイトに関する最後の部分を引用します。
Private Bytes は、実行可能ファイルが使用しているメモリ量の合理的な概算であり、メモリ リークの潜在的な候補のリストを絞り込むのに役立ちます。数値が絶え間なく絶え間なく増加している場合は、そのプロセスでリークが発生していないかどうかを確認する必要があります。ただし、これは漏れがあるかどうかを証明するものではありません。
リンクされたトピックの残りの部分を考慮すると、「プライベート バイト」には、リンクされたアンマネージ dll によって割り当てられたメモリが含まれる場合と含まれない場合があるため、次のようになります。
非管理メモリに関する情報も報告するようにANTSを構成しました(モジュールセクションによる非管理メモリの内訳)。次の2つのモジュールの1つ(特定のsessionfactory設定に応じて)がますます多くのスペースを占めることに気付きました(互換性のある比率で)約 1 週間でコンピューターのメモリが不足します) :
- sqlceqp35
- MSVCR120
現在の結果を考慮して、次のテストを計画しています。
- 休止状態のバージョンを更新する
- 現在の nhibernate sessionhelper 構成をさらに分析しようとしています
- WPF ユーザー インターフェイスなしで空のコンソール アプリケーションを作成する (はい、このアプリケーションは WPF を使用します) 問題を再現できるようになるまでコードを追加します。
なにか提案を?
編集 30/06/2016:
セッションファクトリの初期化は次のとおりです。
SESSION FACTORY: (カスタム ドライバーは、4000 文字以降の切り捨てを回避するためのものです)
factory = Fluently.Configure()
.Database(MsSqlCeConfiguration.Standard.ConnectionString(connString)
.ShowSql()
.MaxFetchDepth(3)
.Driver<MySqlServerCeDriver>()) // FIX truncation 4000 chars
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.ProxyFactoryFactory<NHibernate.ByteCode.LinFu.ProxyFactoryFactory>()
.ExposeConfiguration(c =>
{
c.SetProperty("cache.provider_class", "NHibernate.Cache.HashtableCacheProvider");
c.SetProperty("cache.use_query_cache", "true");
c.SetProperty("command_timeout", "120");
})
.BuildSessionFactory();
public class MySqlServerCeDriver : SqlServerCeDriver
{
protected override void InitializeParameter(
IDbDataParameter dbParam,
string name,
SqlType sqlType)
{
base.InitializeParameter(dbParam, name, sqlType);
if (sqlType is StringClobSqlType)
{
var parameter = (SqlCeParameter)dbParam;
parameter.SqlDbType = SqlDbType.NText;
}
}
}
編集 07/07/2016
要求に応じて、GetSession() は次のことを行います。
public static ISession GetSession()
{
ISession session = factory.OpenSession();
session.FlushMode = FlushMode.Commit;
return session;
}