Утилита: P

много вопросов, которые задают вопрос, как обнаружить утечку идентифицируемых объектов. Похоже, ответ"ты не можешь".

Я только что проверил самый простой тестовый пример, что FxCop 10.0 этого не делает, ReSharper 4 с MSVS2010 этого не делает.

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

Я думал: возможно ли, используя рефлексию и другие непонятные передовые методы, что я могу внедрить проверку во время выполнения в финализаторе, чтобы увидеть,Dispose был вызван?

Как насчет фокусов с WinDBG + SOS?

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

Идеи?

НОТА Название этого вопроса могло вводить в заблуждение. Настоящий вопрос здесь должен бытьбудьIDisposable объект былDisposed() должным образом, Распоряжение GC не считается, так как я считаю это ошибкой.

редактировать: Решение: .NET Memory Profiler делает свою работу. Нам просто нужно спамить несколькоGC.Collect() в конце программы, чтобы наш профилировщик мог правильно подобрать статистику.

 Nick Strupat31 окт. 2011 г., 20:36
Я обдумывал это немного. Я разработал привычку быстро проверять типы, когда пишу код, чтобы увидеть, наследуются ли они отIDisposable, Если они сделают, я заверну ихusing в том объеме, в котором они должны жить. Это ничего не делает для существующего кода, но я просто подумал, что упомяну это.
 John Dyer09 мая 2016 г., 16:36
Взгляните на этот пост, где вы можете использовать анализ кода Visual Studio для обнаружения проблем с iDisposable во время компиляции:stackoverflow.com/a/6213977/2862
 Konrad Rudolph19 янв. 2011 г., 17:23
Причина, по которой инструменты существуют для C ++, но, возможно, не для C #, заключается в том, что ресурсы в C # принципиально отличаются, поскольку неуправляемые ресурсыбольше не связан с продолжительностью жизни объекта, Что можно отследить как в C #, так и в C ++, так это время жизни объекта и правильность его удаления. Но одноразовые ресурсы в C # никак не связаны с временем жизни объекта, что значительно усложняет их отслеживание. Для сравнения попробуйте отследить просочившиеся ресурсы GDI, которые не связаны через RAII, с временем жизни объекта в C ++. Не так просто.

Ответы на вопрос(3)

добавив Finalizer к вашим IDisposable объектам. В финализаторе вы можете проверить, был ли удален объект или нет. Если он не был утилизирован, вы можете заявить об этом или записать что-либо в журнал, или что-то еще.

 ~Disposable()
 {
#if DEBUG
            // In debug-builds, make sure that a warning is displayed when the Disposable object hasn't been
            // disposed by the programmer.

            if( _disposed == false )
            {
                System.Diagnostics.Debug.Fail ("There is a disposable object which hasn't been disposed before the finalizer call: {0}".FormatString (this.GetType ().Name));
            }
#endif
            Dispose (false);
 }

Вы можете включить эту функциональность в базовый класс -Disposable- например, который может быть использован в качестве шаблона для реализацииодноразовый образец например.

Вот так, например:

    /// <summary>
    /// Abstract base class for Disposable types.    
    /// </summary>
    /// <remarks>This class makes it easy to correctly implement the Disposable pattern, so if you have a class which should
    /// be IDisposable, you can inherit from this class and implement the DisposeManagedResources and the
    /// DisposeUnmanagedResources (if necessary).
    /// </remarks>
    public abstract class Disposable : IDisposable
    {
        private bool                    _disposed = false;

        /// <summary>
        /// Releases the managed and unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose (true);
            GC.SuppressFinalize (this);
        }

        /// <summary>
        /// Releases the unmanaged and managed resources.
        /// </summary>
        /// <param name="disposing">When disposing is true, the managed and unmanaged resources are
        /// released.
        /// When disposing is false, only the unmanaged resources are released.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage ("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")]
        protected void Dispose( bool disposing )
        {
            // We can suppress the CA1063 Message on this method, since we do not want that this method is 
            // virtual.  
            // Users of this class should override DisposeManagedResources and DisposeUnmanagedResources.
            // By doing so, the Disposable pattern is also implemented correctly.

            if( _disposed == false )
            {
                if( disposing )
                {
                    DisposeManagedResources ();
                }
                DisposeUnmanagedResources ();

                _disposed = true;
            }
        }

        /// <summary>
        /// Override this method and implement functionality to dispose the 
        /// managed resources.
        /// </summary>
        protected abstract void DisposeManagedResources();

        /// <summary>
        /// Override this method if you have to dispose Unmanaged resources.
        /// </summary>
        protected virtual void DisposeUnmanagedResources()
        {
        }

        /// <summary>
        /// Releases unmanaged resources and performs other cleanup operations before the
        /// <see cref="Disposable"/> is reclaimed by garbage collection.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage ("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")]
        ~Disposable()
        {
#if DEBUG
            // In debug-builds, make sure that a warning is displayed when the Disposable object hasn't been
            // disposed by the programmer.

            if( _disposed == false )
            {
                System.Diagnostics.Debug.Fail ("There is a disposable object which hasn't been disposed before the finalizer call: {0}".FormatString (this.GetType ().Name));
            }
#endif
            Dispose (false);
        }
    }
 TrueWill26 авг. 2011 г., 03:41
@ kizzx2 - финализаторыне неизбежно. Большинство IDisposable классов не нуждаются в финализаторе. Для многих остальных будет достаточно потомков SafeHandle. Прочтите рекомендации Microsoft по этой теме.
 Neil09 июн. 2011 г., 18:59
Финализаторы вводят штрафы за производительность, которые могут быть неприемлемы, учитывая подразумеваемые цели вопроса. CLR Джеффри Рихтера в C # 2nd Edition (стр. 477) указывает, что объекты с финализаторами занимают больше времени, выделяются на более старшие поколения (поэтому они собираются позже) и требуют дополнительной обработки во время сбора.
 TrueWill25 авг. 2011 г., 19:48
@ Нил Уитакер прав. ВидетьРуководство по проектированию конструкции 2-е изд. С. 329-330. «ИЗБЕГАЙТЕ делать типы финализируемыми». Цитируя Джо Даффи: «На сильно загруженном сервере вы можете обнаружить, что один процессор тратит 100% своего времени только на запуск финализаторов».
 TrueWill26 авг. 2011 г., 04:43
@ kizzx2 - но пример кода показывает#if DEBUG внутри финализатор и ответ предлагает использовать это «в качестве шаблона для реализации одноразового шаблона».
 kizzx220 янв. 2011 г., 15:24
Я не думаю, что это плохой подход. На самом деле, я думаю, что этодалеко превосходный подход, чем использование профилировщика для чего-то такого простого в реализации. Единственным недостатком этого является то, что он не может проверять классы других людей, поэтому профилировщик все еще необходим. Но почему бы не выбрать более легкий выход, когда вы можете контролироватьDebug.Assert в вашем финализаторе? Вам действительно нравится все время запускать программу в профилировщике, чтобы поймать несколько небрежных ошибок? Интересно, какая разработка программного обеспечения может сделать этот тривиальный подход «слишком сложным и сложным» по сравнению: P

я считаю, что использование полноценного профилировщика слишком тяжело.

Я создал свое решение для домашнего приготовления:EyeDisposable, Это инструменты сборки, чтобы обнаружить, когдаDispose не был вызван.

 kizzx204 окт. 2014 г., 14:10
@OhadSchneider Спасибо за внимание - статический анализ был бы классным, но он должен иметь много ложных срабатываний для нетривиальных случаев - и, честно говоря, он слишком сложен, чем первоначальный объем этогонебольшой Утилита: P
 Ohad Schneider04 окт. 2014 г., 13:41
Спасибо, выглядит довольно круто! Я бы любилстатический анализ для этого хотя (возможно, как плагин R #). Один небольшой комментарий вклонирование раздел readme нужно запуститьgit submodule init доgit submodule update.
Решение Вопроса

амяти .NET, которые будут смотреть на вашу программу во время ее работы и сообщать вам, где / как используется ваша память (и что у нее течет).

Я хотел бы проверить любой из следующих:

Microsoft CLR Memory Profiler (бесплатно)
RedGate ANTS Профилировщик памяти
JetBrain's DotTrace (также включает в себя профилировщик кода)
SciTech .NET Memory Profiler

Обновить

SciTech .NET Memory Profiler имеет функцию под названием «Dispose Tracker», которая отвечает требованиям для запроса OP на отслеживание только вызовов Dispose в их приложении.

 kizzx219 янв. 2011 г., 17:02
@Uwe Keim: отслеживает ли профилировщик памяти ANTS от RedGate, что на самом деле задал вопрос? (Это единственный в списке, который требует отправки электронной почты для оценки - слишком ленив, чтобы сделать это прямо сейчас)
 Uwe Keim19 янв. 2011 г., 16:46
У меня был лучший опыт работы с ANG Memory Profiler от RedGate.
 kizzx219 янв. 2011 г., 16:31
Это обнаруживаетDispose или просто память? Что делать, если мойIDisposable объект просто имеетConsole.WriteLine("baz"); (плохой пример, я знаю, но вы понимаете, в чем дело) и я хочу убедиться, что он на самом деле называется НЕ GC?
 kizzx219 янв. 2011 г., 17:11
У .NET Memory Profiler есть эта функция под названием «Dispose Tracker», которая делает именно то, что я хотел. К сожалению, этот ответ в его нынешнем виде никому не нужен, потому что он просто перечисляет результаты поиска Google (не то, чтобы это было бесполезно - он заставил меня пойти вниз и попробовать каждый из них, чтобы доказать, что хотя бы один из них актуален ). Можете ли вы отредактировать его, по крайней мере, для включения «Dispose Tracker» о .NET Memory Profiler, чтобы это было как минимум информативно?
 Justin Niessner19 янв. 2011 г., 16:31
@ kizzx2 - Он обнаружит все, но оттуда вы можете сузить его, чтобы найти то, что вы ищете.

Ваш ответ на вопрос