我正在调试一个现有的windows服务(用C语言编写),它需要每隔几个月手动重启一次,因为它一直在消耗内存。
接下来,它将这个json文件解析为产品列表。
对于每种产品,它都会检查数据库中是否已经存在该产品。如果不存在,则会添加。如果存在,则会更新属性。
该数据库是一个PostgreSQL数据库,我们使用NHibernate v3.2.0作为ORM。
我一直在使用JetBrains DotMemory在服务运行时对其进行评测:
服务开始,30秒后开始工作。快照#1在第一次运行之前创建。
快照#6是在第5次运行后制作的。
其他快照也在运行后生成。
正如您可以看到的那样,每次运行后,对象的数量增加了约60k,使用的内存在每次运行后增加了几MB。
仔细观察快照#6,可以发现保留的大小主要由NHibernate会话对象使用:
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);
}
我的DoService工作:
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);
}
和a
EndSession
:
ISession session = ThreadLocalSessionContext.Unbind(_sessionFactory);
if (session != null)
{
session.Close();
}
在我的数据访问类中,我调用
base.BeginSession
在开始和
base.EndSession
然后结束。