使用NHibernate的Windows服务正在增加使用的内存

时间:2017-11-15 13:06:33

标签: c# memory nhibernate dotmemory

我正在调试现有的Windows服务(用C#编写),需要每隔几个月手动重启一次,因为它会继续占用内存。

服务不是很复杂。它从外部服务器请求一个json文件,该服务器保存产品。 接下来,它将此json文件解析为产品列表。 对于这些产品中的每一个,它都在检查该产品是否已存在于数据库中。如果不存在,如果它存在则将被添加,属性将被更新。

数据库是PostgreSQL数据库,我们使用NHibernate v3.2.0作为ORM。

我一直在使用JetBrains DotMemory在服务运行时对其进行分析: DotMemory overvies

服务开始,30年后它开始工作。 SnapShot#1是在第一次运行之前制作的。 快照#6是在第5次运行后制作的。 其他快照也在运行后生成。 正如您在每次运行后看到的那样,对象的数量会增加大约。每次运行后,60k和使用的内存会增加几MB。

仔细观察Snapshot#6,可以看出保留的大小主要由NHibernate会话对象使用:

Snapshot #6

这是我的OnStart代码:

try
{
    // Trying to fix certificate errors:
    ServicePointManager.ServerCertificateValidationCallback += delegate
    {
        _logger.Debug("Cert validation work around");
        return true;
    };

    _timer = new Timer(_interval)
    {
        AutoReset = false // makes it fire only once, restart when work is done to prevent multiple runs
    };
    _timer.Elapsed += DoServiceWork;
    _timer.Start();
}
catch (Exception ex)
{
    _logger.Error("Exception in OnStart: " + ex.Message, ex);
}

我的DoServiceWork:

try
{
    // Call execute
    var processor = new SAPProductProcessor();
    processor.Execute();
}
catch (Exception ex)
{
    _logger.Error("Error in DoServiceWork", ex);
}
finally
{
    // Next round:
    _timer.Start();
}

在SAPProductProcessor中,我使用两个db调用。两者都在循环中。 我遍历JSON文件中的所有产品,并使用产品代码检查产品是否已在表中:

ProductDto dto;
using (var session = SessionFactory.OpenSession())
{
    using (var transaction = session.BeginTransaction(IsolationLevel.ReadCommitted))
    {
        var criteria = session.CreateCriteria<ProductDto>();
        criteria.Add(Restrictions.Eq("Code", code));
        dto = criteria.UniqueResult<ProductDto>();
        transaction.Commit();
    }
}
return dto;

当productDto更新时,我使用以下方法保存:

using (var session = SessionFactory.OpenSession())
{
    using (var transaction = session.BeginTransaction(IsolationLevel.ReadCommitted))
    {
        session.SaveOrUpdate(item);
        transaction.Commit();
    }
}

我不确定如何更改上面的代码以停止增加内存和对象数量。

我已尝试使用var session = SessionFactory.GetCurrentSession();代替using (var session = SessionFactory.OpenSession()),但这并没有阻止内存的增加。

更新

在我的数据访问类MultiSessionFactoryProvider sessionFactoryProvider的构造函数中注入。并使用: base(sessionFactoryProvider.GetFactory("data"))调用基类。该基类有一个方法BeginSession

ISession session = _sessionFactory.GetCurrentSession();
if (session == null)
{
  session = _sessionFactory.OpenSession();
  ThreadLocalSessionContext.Bind(session);
}

EndSession

ISession session = ThreadLocalSessionContext.Unbind(_sessionFactory);
if (session != null)
{
    session.Close();
}

在我的数据访问类中,我在开始时调用base.BeginSession,然后在base.EndSession调用。

1 个答案:

答案 0 :(得分:0)

关于Singleton的建议让我仔细研究了我的数据访问类。

我认为在每次运行时创建这个类会在NHibernate内存超出范围时释放它。我甚至在类的析构函数中添加了一些dispose调用。但这不起作用,或者更可能是我没有正确地做到这一点。 我现在将我的数据访问类保存在静态字段中并重新使用它。现在我的记忆力不再增加,更重要的是打开物体的数量保持不变。我再次使用DotMemory运行服务超过一个小时调用运行150次左右,最后一个快照的内存仍然是105MB左右,对象的数量仍然是117k而我的SessionFactory字典现在只有4MB而不是150 * 4MB