前不久为用户做了一个小工具,把数据中心的数据发布到其它相应的数据库.到用户的测试机上一跑,
10分钟左右,内存用光(1.5G),跟踪看了一下
IBATISN.NET 1.6.1的源码,哈哈。。。找着根了
一、根位置 MappedStatement.cs
ibaits的数据真实操作都交给了这个类。其中用一大堆与select相关操作的方法以及insert update delete相关方法,内存泄漏就在这些方法上。简单看一下ExecuteInsert(insert)方法的代码:
// 初始化 command 的参数
_preparedCommand.Create(request, session, this.Statement, parameterObject);
// 用 using 处理 command
using (IDbCommand command = request.IDbCommand)
{
try
{
if (_statement is Insert)
{
generatedKey = command.ExecuteNonQuery();
}
// Retrieve output parameter if the result class is specified
else if (_statement is Procedure && (_statement.ResultClass != null) &&
_sqlMap.TypeHandlerFactory.IsSimpleType(_statement.ResultClass))
{
......// 省
}
if (selectKeyStatement != null && selectKeyStatement.isAfter)
{
IMappedStatement mappedStatement = _sqlMap.GetMappedStatement(selectKeyStatement.Id);
generatedKey = mappedStatement.ExecuteQueryForObject(session, parameterObject);
ObjectProbe.SetMemberValue(parameterObject, selectKeyStatement.PropertyName, generatedKey,
request.DataExchangeFactory.ObjectFactory,
request.DataExchangeFactory.AccessorFactory);
}
//ExecutePostSelect(request);
RetrieveOutputParameters(request, session, command, parameterObject);
}
// 下面这个 finally 段是我加上去的,我不确定 command 的 dispose是否会调用相关Paramters中对象相应的 dispose 方法,所以就用了下面这个,因为程序中显示大量IDataParamter 对象无法回收
finally
{
if (command.Parameters.Count > 0){
MethodInfo mi = command.Parameters[0].GetType().GetMethod("Dispose", BindingFlags.Instance | BindingFlags.Public);
if (mi != null)
for (int i = 0; i < command.Parameters.Count; i++)
mi.Invoke(command.Parameters[i], null);
}
command.Dispose();
}
}
二、原因 IDispose 接口得显示调用
using并不能释放这些非托管资源
三、解决方法:看上面代码
四、总结
以前用ibaits怎么就没有发现在呢?
我想这与项目的实际应用场景有关,问题一直都存在,只是没有显现吧了。
大多数据时候,用户的输入参数只有几个,相对较少,而且调用频度应该不高。
而这个应用场景走的却是另一个极端:
调用频度极高:
数据中心实时采集4家公司的数据,且数据更新高峰在开收盘前后,中午休市最为集中,每天的数据更新在3000K左右,这些数据要及时发布到5个数据库中
参数超多:
近200张表中有50多张账务相关的表字段个数在100到230之间
这些字段最终是要转换成 INSERT 与 UPDATE 语句中的参数,
怪不得程序显示超多OarcleParamter 对象无法回收,它不多才怪。。。
不过还好,加了上面的代码后,程序内存近期还没超过150M,多在100M左右
如果你也有用IBAITS.NET,你可要小心了。。
这个问题其实是由 IDispose 接口引起的, 不知道JAVA是什么样子,源码还没仔细看
JAVA版本的3.0出来时间也不短了,易用性比 IBATIS.NET 1.6.1 要强太多了。
不知道 .NET 版本的更新什么时候出。。。