Почему вызов GC.Collect ускоряет процесс

У нас есть библиотека C ++ (без MFC, без ATL), которая обеспечивает некоторые основные функции для нашего приложения .NET. C ++ DLL используется SWIG создать сборку C #, которую можно использовать для доступа к ее классам / методам, используя PInvoke. Эта сборка C # используется в нашем приложении .NET для использования функциональности внутри C ++ DLL.

Проблема связана с утечками памяти. В нашем .NET-приложении у меня есть цикл в моем .NET-коде, который создает тысячи экземпляров определенного класса из C ++ DLL. Цикл продолжает замедляться, поскольку он создает экземпляры, но если я вызываю GC.Collect () внутри цикла (что, я знаю, не рекомендуется), обработка становится быстрее. Почему это? Вызов Dispose () для типов не влияет на скорость. Я ожидал снижения скорости программы при использовании GC.Collect (), но это как раз наоборот.

Каждый класс, который генерирует SWIG, имеет деструктор ~, который вызывает Dispose (). Каждый метод Dispose имеет блокировку (this) вокруг операторов, которые выполняют вызовы для удаления неуправляемой памяти. Наконец это вызывает GC.SuppressFinalize. Мы также видим AccessViolationException спорадически в сборках Release. Любая помощь будет оценена.

2

Решение

Некоторые типы объектов могут убирать за собой (через Finalize) если они оставлены без утилизации, но их хранение может быть дорогостоящим, пока финализатор не дойдет до них; Одним из примеров в рамках Framework является перечислитель, возвращаемый Microsoft.VisualBasic.Collection.GetEnumerator(), Каждый звонок GetEnumerator() прикрепит объект, обернутый новым объектом перечислителя, к различным частным событиям обновления, управляемым коллекцией, когда перечислитель Disposeг, он откажется от своих событий. Если GetEnumerator() вызывается многократно (например, многие тысячи или миллионы) без удаления перечислителей и без промежуточной сборки мусора, сборка будет выполняться медленнее и медленнее (в сотни или тысячи раз медленнее, чем обычно), поскольку список подписки на события продолжает расти. Однако, когда происходит сборка мусора, любые оставленные счетчики Finalize методы очистят свои подписки, и все снова начнет работать прилично.

Я знаю, что вы сказали, что звоните Dispose, но у меня есть подозрение, что что-то создает IDisposable экземпляр объекта и не вызывающий Dispose в теме. Если IDisposable учебный класс Foo создает и владеет экземпляром IDisposable учебный класс Bar, но Foo не Dispose этот экземпляр в своем собственном Dispose реализация, вызов Dispose на примере Foo не будет убирать Bar, Однажды Foo заброшен, был ли он Disposeд, его Bar в конечном итоге будет оставлен без утилизации.

1

Другие решения

Вы вызываете GC.SupressFinalize в вашем методе Dispose? Во всяком случае, есть хорошая статья MSDN, которая объясняет, как написать дружественный GC код — Основы сборки мусора и советы по производительности. Может быть, это будет полезно.

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector