We've an application which writes records in a SQL Server CE (version 3.5) / (MySQL 5.7.11 community) database table [depending on the configuration] through the use of NHibernate (version 3.1.0.4000).
The method which performs the save to the database table has the following structure, so everything should be disposed correctly
using (ISession session = SessionHelper.GetSession())
using (ITransaction txn = session.BeginTransaction())
{
session.Save(entity);
txn.Commit();
}
After about a week of heavy work (where several hundred thousands records have been written) the application stops working and throws an out of memory error.
Then:
- With SQL Server CE the database gets corrupted and needs to be manually repaired
- With MySQL the mysqld daemon is terminated and it needs to be restarted
We've been monitoring the application memory usage through ANTS Memory Profiler (with SQL CE configuration), but, to our surprise, the application "private bytes" doesn't seem to increase at all - this is reported both by ANTS and by the RESOURCE MANAGER.
Still, when the application is forced close (after such error shows up) the "physical memory usage" in the task manager falls from about 80% right down to 20-30%, and I'm again able to start other processes without getting another out of memory exception.
Doing some research, I've found this:
What is private bytes, virtual bytes, working set?
I quote the last part about private bytes:
Private Bytes are a reasonable approximation of the amount of memory your executable is using and can be used to help narrow down a list of potential candidates for a memory leak; if you see the number growing and growing constantly and endlessly, you would want to check that process for a leak. This cannot, however, prove that there is or is not a leak.
Considering the rest of the linked topic, for what I understand, "private bytes" may or may not contain the memory allocated by linked unmanaged dlls, so:
I configured ANTS to also report information about unmanaged memory (Unmanaged memory breakdown by module section) and I've noticed that one of the 2 following modules (depending on a specific sessionfactory setting) take up more and more space (with a ratio that's compatible with the computer running out of memory in about a week):
- sqlceqp35
- MSVCR120
Given the current results, I'm planning the following tests:
- update nhibernate version
- trying to further analyze current nhibernate sessionhelper configuration
- creating an empty console application without WPF user interface (yes, this application uses WPF) where I put more and more code until I'm able to reproduce the issue
Any suggestion?
EDIT 30/06/2016:
Here's the session factory initialization:
SESSION FACTORY: (the custom driver is to avoid trucation after 4000 chars)
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;
}
}
}
EDIT 07/07/2016
As requested, the GetSession() does the following:
public static ISession GetSession()
{
ISession session = factory.OpenSession();
session.FlushMode = FlushMode.Commit;
return session;
}