NHibernate consuming lots of memory

1

I have an application that connects to the database via NHibernate , so some operations are performed as Save, Update e Delete . But when performing these procedures it is incredible how memory accumulation is done by not automatically performing the memory wipe with the GC not used by the CLR.

For example: A query that returns an average of 1000 rows accumulates on average 100mb of memory, is this normal?

The implementation of the connection code with the base is done as follows:

  public ISession OpenConnection<T>(SelectDb dbConfigKey, DatabaseType dbType)
    {
        ISessionFactory sessionFactory = null;

        try
        {
            switch (dbType)
            {
                #region Conexão com a base de dados SQL Server 2000
                case DatabaseType.SQLServer2000:
                    sessionFactory = Fluently.Configure()
                    .Database(MsSqlConfiguration.MsSql2000
                      .ConnectionString(dbConfigKey.ToDescriptionDatabase())
                                  .ShowSql()
                    )
                   .Mappings(m =>
                              m.FluentMappings
                                  .AddFromAssemblyOf<T>())
                    .ExposeConfiguration(cfg => new SchemaExport(cfg)
                                                    .Create(false, false))
                    .BuildSessionFactory();
                    break;
                #endregion

                #region Conexão com a base de dados SQL Server 2008
                case DatabaseType.SQLServer2008:
                    sessionFactory = Fluently.Configure()
                    .Database(MsSqlConfiguration.MsSql2008
                      .ConnectionString(dbConfigKey.ToDescriptionDatabase())
                                  .ShowSql()
                    )
                   .Mappings(m =>
                              m.FluentMappings
                                  .AddFromAssemblyOf<T>())
                    .ExposeConfiguration(cfg => new SchemaExport(cfg)
                                                    .Create(false, false))
                    .BuildSessionFactory();
                    break;
                #endregion

                #region Conexão com a base de dados PostgreSQL
                case DatabaseType.PostgreSQL:
                    sessionFactory = Fluently.Configure()
                    .Database(PostgreSQLConfiguration.Standard
                      .ConnectionString(dbConfigKey.ToDescriptionDatabase())
                                  .ShowSql()
                    )
                   .Mappings(m =>
                              m.FluentMappings
                                  .AddFromAssemblyOf<T>())
                    .ExposeConfiguration(cfg => new SchemaExport(cfg)
                                                    .Create(false, false))
                    .BuildSessionFactory();
                    break;
                #endregion

                #region Conexão com a base de dados MYSQL
                case DatabaseType.MYSQL:
                    sessionFactory = Fluently.Configure()
                    .Database(MySQLConfiguration.Standard
                      .ConnectionString(dbConfigKey.ToDescriptionDatabase())
                                  .ShowSql()
                    )
                   .Mappings(m =>
                              m.FluentMappings
                                  .AddFromAssemblyOf<T>())
                    .ExposeConfiguration(cfg => new SchemaExport(cfg)
                                                    .Create(false, false))
                    .BuildSessionFactory();
                    break;
                #endregion

                #region Conexão com a base de dados Oracle9
                case DatabaseType.Oracle9:
                    sessionFactory = Fluently.Configure()
                    .Database(OracleClientConfiguration.Oracle9
                      .ConnectionString(dbConfigKey.ToDescriptionDatabase())
                                  .ShowSql()
                    )
                   .Mappings(m =>
                              m.FluentMappings
                                  .AddFromAssemblyOf<T>())
                    .ExposeConfiguration(cfg => new SchemaExport(cfg)
                                                    .Create(false, false))
                    .BuildSessionFactory();
                    break;
                #endregion

                #region Conexão com a base de dados Oracle10
                case DatabaseType.Oracle10:
                    sessionFactory = Fluently.Configure()
                    .Database(OracleClientConfiguration.Oracle10
                      .ConnectionString(dbConfigKey.ToDescriptionDatabase())
                                  .ShowSql()
                    )
                   .Mappings(m =>
                              m.FluentMappings
                                  .AddFromAssemblyOf<T>())
                    .ExposeConfiguration(cfg => new SchemaExport(cfg)
                                                    .Create(false, false))
                    .BuildSessionFactory();
                    break;
                #endregion


            }


        }
        catch (Exception)
        {
            sessionFactory.Close();
            sessionFactory.Dispose();
        }
        return sessionFactory.OpenSession();
    }

where public ISession OpenConnection (SelectDb dbConfigKey, DatabaseType dbType) receives a class and passes parameter to database configuration and connection type.

Any tips for using Nhibernate for this kind of purpose?

    
asked by anonymous 19.02.2018 / 18:51

1 answer

1

The CLR does not do the automatic cleaning in this case, so the Dipose and Close.

Database connection frameworks "bundles" all complicated work of allocating memory on the server, making a connection to the database, etc. This whole job is done outside the .Net Runtime, which is why it is considered as an unmanaged resource .

So the Garbage Collector is not aware of this unmanaged resource and can not efficiently clean them (thinking that there is a way to clean this resource inside a finisher of the object that bundles it). Because of this you are very likely to have problems with memory leak.

The .Dispose () and .Close () should be inside the finally block, since you are not closing the connection to the database in cases where an exception does not occur.

try {
...
}
catch (Exception)
{
...
}
finally {
    //Faz o tratamento caso o seu switch cair em default por algum motivo.
    if (sessionFactory != null) {
        sessionFactory.Close();
        sessionFactory.Dispose();
    }
}

On issues related to NHibernante's performance, I owe it already since I've never worked with it.

    
19.02.2018 / 21:19