我们有一个应用程序,它通过使用 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();
}
经过大约一周的繁重工作(已写入数十万条记录),应用程序停止工作并引发内存不足错误。
然后:
- 使用 SQL Server CE,数据库损坏,需要手动修复
- 使用 MySQL,mysqld 守护进程已终止,需要重新启动
我们一直在通过 ANTS Memory Profiler(使用 SQL CE 配置)监控应用程序内存使用情况,但令我们惊讶的是,应用程序“私有字节”似乎根本没有增加——ANTS 和资源经理。
尽管如此,当应用程序被强制关闭时(在出现此类错误之后),任务管理器中的“物理内存使用率”从大约 80% 下降到 20-30%,并且我再次能够启动其他进程而无需获得另一个内存不足异常。
做了一些研究,我发现了这个:
我引用了关于私有字节的最后一部分:
Private Bytes 是可执行文件正在使用的内存量的合理近似值,可用于帮助缩小内存泄漏的潜在候选者列表;如果您看到这个数字不断增长且无休止地增长,您会想要检查该过程是否存在泄漏。但是,这不能证明存在或不存在泄漏。
考虑到链接主题的其余部分,据我所知,“私有字节”可能包含也可能不包含链接的非托管 dll 分配的内存,因此:
我将 ANTS 配置为还报告有关非托管内存的信息(按模块部分划分的非托管内存细分),我注意到以下 2 个模块之一(取决于特定的 sessionfactory 设置)占用越来越多的空间(具有兼容的比率大约一周后计算机内存不足):
- sqlceqp35
- MSVCR120
鉴于目前的结果,我计划进行以下测试:
- 更新休眠版本
- 试图进一步分析当前的 nhibernate sessionhelper 配置
- 创建一个没有 WPF 用户界面的空控制台应用程序(是的,此应用程序使用 WPF)我在其中放置了越来越多的代码,直到我能够重现该问题
有什么建议吗?
编辑 2016 年 6 月 30 日:
这是会话工厂初始化:
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;
}