Как уменьшить использование памяти в Enterprise Library 5.0? - PullRequest
1 голос
/ 25 января 2012

Я использую Enterprise Logging 5.0 в консольном приложении .net 4.0.Я заметил очень высокое использование памяти в моем приложении.Я смог определить, что причина была в следующем вызове:

var logWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();

После некоторого профилирования и ручного тестирования с помощью простого консольного приложения я смог определить, что использование памяти сократилось с 45 МБ.до 10 МБ , когда из папки выполнения были удалены следующие библиотеки:

  • Microsoft.Practices.EnterpriseLibrary.Validation.dll
  • Microsoft.Practices.EnterpriseLibrary.Data.dll

Инициализация журнала - это мой первый вызов API библиотеки Enterprise.Мое консольное приложение не выполняет никаких вызовов Data.dll и Validation.dll.Они существуют в моей папке выполнения, потому что они являются ссылками для других библиотек классов и нашей установки развертывания.

Я предполагаю, что EnterpriseLibraryContainer.Current инициализируется на основе того, что находится в папке выполнения.Я попытался создать свой logwriter со следующим, но я получил тот же результат:

var configSource = new FileConfigurationSource(configPath);          
var logWriterFactory = new LogWriterFactory(configSource);
var logWriter = logWriterFactory.Create();

Можно ли инициализировать logwriter без увеличения использования памяти с проверкой и данными 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 .(о котором я не упомянул с самого начала)

(мое текущее выполнение приложения не вызывает и не ссылается на доступ к данным, строки подключения определены, потому что приложение использует динамические вызовы для других библиотек, которым нужны строки подключения., но длямой тест Я не вызываю ни один из этих вызовов)

Поскольку 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;
    }

Вызов DbProviderFactories.GetFactory (dbProviderName) приdbProviderName = Oracle.DataAccess.Client.OracleClientFactory вызывает огромный всплеск памяти.

Похоже, что причиной огромного скачка памяти является odp.net и тот факт, что его регистрация DBFactories,

Кажется, что я не могу создать регистратор, не зарегистрировав все присутствующее в месте выполнения сборки.В идеале я не хотел бы регистрировать доступ к данным, если это явно не указано.

1 Ответ

1 голос
/ 26 января 2012

Тот факт, что ODP.NET используется в качестве основного поставщика, является основной причиной скачка памяти, и GetDefaultMapping в любом случае будет возвращать ноль. Следующее изменение может быть сделано:

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;


        if (dbProviderName != "Oracle.DataAccess.Client")
        {
            // 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;
    }

Это все еще не объясняет, почему Oracle.DataAccess.Client использует так много памяти для:

DbProviderFactories.GetFactory(dbProviderName);

а также почему он регистрирует доступ к данным в контейнере.

...