【发布时间】:2012-02-18 07:15:27
【问题描述】:
我在 .net 4.0 控制台应用程序中使用企业日志记录 5.0。我注意到我的应用程序中的内存使用率非常高。我能够确定原因是由于以下调用:
var logWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();
在使用简单的控制台应用程序进行一些分析和手动测试后,我能够确定当从执行文件夹中删除以下 dll 时,内存使用量从 45mb 下降到 10mb:
- Microsoft.Practices.EnterpriseLibrary.Validation.dll
- Microsoft.Practices.EnterpriseLibrary.Data.dll
日志初始化是我第一次调用企业库 api。我的控制台应用程序不调用 Data.dll 和 Validation.dll。它们存在于我的执行文件夹中,因为它们是其他类库和我们的部署设置的引用。
我假设 EnterpriseLibraryContainer.Current 正在根据在执行文件夹中找到的内容进行初始化。我尝试使用以下内容创建我的记录器,但得到了相同的结果:
var configSource = new FileConfigurationSource(configPath);
var logWriterFactory = new LogWriterFactory(configSource);
var logWriter = logWriterFactory.Create();
是否可以在不增加内存使用量的情况下使用执行文件夹中存在的验证和数据 dll 来初始化日志写入器?
更新: 因此,在 entlib 源代码中进行了一些调试之后。我相信以下是找到 dll 并实例化 Validation.dll 和 Data.dll,尽管在项目中根本没有引用。
来自 EntLib50Src\Blocks\Common\Src\Configuration\ContainerModel\TypeLoadingLocator.cs
private IEnumerable<TypeRegistration> GetRegistrationsInternal(IConfigurationSource configurationSource,
Func<ITypeRegistrationsProvider, IConfigurationSource, IEnumerable<TypeRegistration>> registrationAccessor)
{
Type providerType = Type.GetType(Name);
if (providerType == null) return new TypeRegistration[0];
var provider = (ITypeRegistrationsProvider)Activator.CreateInstance(providerType);
return registrationAccessor(provider, configurationSource);
}
对 Type.GetType(Name) 的调用会查看 Executing Assembly 位置,这似乎是它注册 entlib 数据访问的原因。
进一步调试我的原始应用程序后,该应用程序包含与 Oracle ODP.net 提供程序 的连接字符串。 (我从一开始就没有提到)
(我当前的应用程序执行没有调用或引用数据访问,定义了连接字符串,因为应用程序使用动态调用需要连接字符串的其他 dll。但对于我的测试,我没有调用任何这些调用)
自从找到 Microsoft.Practices.EnterpriseLibrary.Data.dll 后,EnterpriseLibrary 继续默认注册数据访问类型,我发现以下调用是导致巨大内存峰值的原因:
\EntLib50Src\Blocks\Data\Src\Data\Configuration\DatabaseSyntheticConfigSettings.cs
private static DbProviderMapping GetDefaultMapping(string dbProviderName)
{
// try to short circuit by default name
if (DbProviderMapping.DefaultSqlProviderName.Equals(dbProviderName))
return defaultSqlMapping;
if (DbProviderMapping.DefaultOracleProviderName.Equals(dbProviderName))
return defaultOracleMapping;
// get the default based on type
var providerFactory = DbProviderFactories.GetFactory(dbProviderName);
if (SqlClientFactory.Instance == providerFactory)
return defaultSqlMapping;
if (OracleClientFactory.Instance == providerFactory)
return defaultOracleMapping;
return null;
}
当 dbProviderName=Oracle.DataAccess.Client.OracleClientFactory 时调用 DbProviderFactories.GetFactory(dbProviderName) 会导致巨大的内存峰值。
所以看起来巨大的内存峰值的原因是由于 odp.net 以及它注册 DBFactories 的事实。
如果不注册执行程序集位置中存在的所有内容,我似乎无法创建记录器。理想情况下,除非明确告知,否则我不想注册数据访问权限。
【问题讨论】:
-
还在这里创建了一个讨论:entlib.codeplex.com/discussions/287422
标签: c#-4.0 logging memory-management enterprise-library