Исключение нехватки памяти после определенного времени выполнения, но частные байты приложения С# не увеличиваются

У нас есть приложение, которое записывает записи в таблицу базы данных SQL Server CE (версия 3.5)/(сообщество MySQL 5.7.11) [в зависимости от конфигурации] с помощью NHibernate (версия 3.1.0.4000).

Метод, выполняющий сохранение в таблицу базы данных, имеет следующую структуру, поэтому все должно быть правильно расставлено

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%, и я снова могу запускать другие процессы, не получая еще одно исключение нехватки памяти.

Проведя некоторые исследования, я нашел это:

Что такое частные байты, виртуальные байты, рабочий набор?< /а>

Я цитирую последнюю часть о приватных байтах:

Частные байты — это разумное приближение объема памяти, используемого вашим исполняемым файлом, и его можно использовать, чтобы помочь сузить список потенциальных кандидатов на утечку памяти; если вы видите, что число растет и растет постоянно и бесконечно, вы захотите проверить этот процесс на утечку. Однако это не может доказать наличие или отсутствие утечки.

Учитывая остальную часть связанной темы, насколько я понимаю, «частные байты» могут содержать или не содержать память, выделенную связанными неуправляемыми dll, поэтому:

Я настроил ANTS так, чтобы он также сообщал информацию о неуправляемой памяти (разбивка неуправляемой памяти по разделам модулей) и заметил, что один из двух следующих модулей (в зависимости от конкретной настройки sessionfactory) занимает все больше и больше места (соотношение, совместимое с тем, что память компьютера заканчивается примерно через неделю):

  1. sqlceqp35
  2. MSVCR120

Учитывая текущие результаты, я планирую следующие тесты:

  1. обновить версию nhibernate
  2. попытка дальнейшего анализа текущей конфигурации nhibernate sessionhelper
  3. создание пустого консольного приложения без пользовательского интерфейса 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;
        }

person Carlo Arnaboldi    schedule 28.06.2016    source источник
comment
Вы, вероятно, где-то утечка системных ресурсов. Без кода не могу помочь. Связано: stackoverflow.com/q/32357314/327083   -  person J...    schedule 28.06.2016
comment
Out of Memory не всегда буквально означает выделенную память. Это часто означает, что дескрипторы, пользовательские или объекты GDI были исчерпаны. Чтобы он работал сотни тысяч раз, я предполагаю, что это может быть чем-то условным.   -  person Ňɏssa Pøngjǣrdenlarp    schedule 28.06.2016
comment
@Plutonix Не обязательно условно - может быть небольшая кумулятивная утечка.   -  person J...    schedule 28.06.2016
comment
@Plutonix Это не кажется чем-то условным, поскольку я изменил исходный код, чтобы он всегда вел себя одинаково: на каждой итерации одна и та же сущность сохраняется снова и снова с помощью кода, приведенного выше (ITransaction .. и т.д)   -  person Carlo Arnaboldi    schedule 30.06.2016
comment
@J ... Я добавил код инициализации sessionfactory, может быть, это поможет. Если вы считаете, что вам могут понадобиться другие части кода, просто дайте мне знать.   -  person Carlo Arnaboldi    schedule 30.06.2016
comment
и что SessionHelper.GetSession() делает под капотом?   -  person Chizh    schedule 30.06.2016
comment
@Chizh делает это: ISession session = factory.OpenSession(); session.FlushMode = FlushMode.Commit; обратная сессия;   -  person Carlo Arnaboldi    schedule 07.07.2016
comment
а фабричное статическое поле? может быть, он хранит все кешированные вещи. подробнее: Почему NHibernate.Cache.HashtableCacheProvider не предназначен для использования в продакшене? stackoverflow.com/a/4298483/225389   -  person Chizh    schedule 07.07.2016
comment
@Chizh спасибо за добрый ответ. Мы изучаем настройку NHibernate.Cache.HashtableCacheProvider, которую, как вы сказали, не следует использовать в производстве. Удаление этого параметра, по-видимому, никак не влияет на утечку памяти, но мы все еще работаем над этим. Я обновлю эту тему, как только у меня будет больше информации   -  person Carlo Arnaboldi    schedule 02.08.2016