Как избавиться от класса в .net?

Сборщик мусора .NET со временем освободит память, но что, если вы хотите немедленно вернуть эту память? Какой код вам нужно использовать в классе MyClass для вызова

MyClass.Dispose()

и освободить все используемое пространство переменными и объектами в MyClass?

Ответов (20)

Решение

IDisposable не имеет ничего общего с освобождением памяти. IDisposable - это шаблон для освобождения неуправляемых ресурсов, а память, безусловно, является управляемым ресурсом.

Ссылки, указывающие на GC.Collect (), являются правильным ответом, хотя использование этой функции обычно не рекомендуется в документации Microsoft .NET.

Изменить: заработав значительную сумму кармы за этот ответ, я чувствую определенную ответственность за его уточнение, чтобы новичок в управлении ресурсами .NET не получил неправильного впечатления.

Внутри процесса .NET есть два вида ресурсов - управляемые и неуправляемые. «Управляемый» означает, что среда выполнения контролирует ресурс, а «неуправляемый» означает, что это ответственность программиста. И сегодня в .NET нам важен только один вид управляемых ресурсов - память. Программист приказывает среде выполнения выделить память, и после этого среда выполнения должна выяснить, когда можно освободить память. Механизм, который .NET использует для этой цели, называется сборкой мусора, и вы можете найти много информации о GC в Интернете, просто используя Google.

Что касается других видов ресурсов, .NET ничего не знает об их очистке, поэтому ему приходится полагаться на программиста, чтобы он поступил правильно. Для этого платформа предоставляет программисту три инструмента:

  1. Интерфейс IDisposable и оператор using в VB и C#
  2. Финализаторы
  3. Шаблон IDisposable, реализованный во многих классах BCL

Первый из них позволяет программисту эффективно получать ресурс, использовать его, а затем выпустить все в одном методе.

using (DisposableObject tmp = DisposableObject.AcquireResource()) {
    // Do something with tmp
}
// At this point, tmp.Dispose() will automatically have been called
// BUT, tmp may still a perfectly valid object that still takes up memory

Если AcquireResource - это фабричный метод, который (например) открывает файл, а Dispose автоматически закрывает файл, то этот код не может вызвать утечку файлового ресурса. Но память для самого объекта "tmp" вполне может быть выделена. Это потому, что интерфейс IDisposable не имеет абсолютно никакого отношения к сборщику мусора. Если вы действительно хотите убедиться, что память была освобождена, ваш единственный вариант - вызвать GC.Collect() принудительную сборку мусора.

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

Что произойдет, если ресурс используется в течение более длительного периода времени, так что его срок службы пересекает несколько методов? Ясно, что оператор «using» больше не применим, поэтому программисту придется вручную вызывать «Dispose», когда он или она закончит работу с ресурсом. А что будет, если программист забудет? Если отката нет, то процесс или компьютер могут в конечном итоге исчерпать ресурсы, которые не были освобождены должным образом.

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

Таким образом, в случае с файлом нам теоретически не нужно закрывать файл вручную. Мы можем просто подождать, пока сборщик мусора не доберется до него, а затем позволить финализатору сделать свою работу. К сожалению, на практике это не работает, потому что сборщик мусора работает недетерминированно. Файл может оставаться открытым значительно дольше, чем ожидает программист. И если открыто достаточно файлов, система может дать сбой при попытке открыть дополнительный файл.

Для большинства ресурсов нам нужны обе эти вещи. Мы хотим, чтобы в соглашении говорилось «мы закончили с этим ресурсом сейчас», и мы хотим быть уверены, что есть хотя бы некоторая вероятность того, что очистка произойдет автоматически, если мы забудем сделать это вручную. Вот где в игру вступает паттерн «IDisposable». Это соглашение, которое позволяет IDispose и финализатору прекрасно взаимодействовать друг с другом. Вы можете увидеть, как работает этот шаблон, посмотрев официальную документацию для IDisposable .

Итог: если вы действительно хотите просто убедиться, что память освобождена, то IDisposable и финализаторы вам не помогут. Но интерфейс IDisposable является частью чрезвычайно важного паттерна, который должны понимать все программисты .NET.

Если MyClass реализует IDisposable, вы можете это сделать.

MyClass.Dispose();

Лучшая практика в C#:

using( MyClass x = new MyClass() ) {
    //do stuff
}

Поскольку это завершает утилизацию в конечном итоге и гарантирует, что ее никогда не пропустят.

Взгляните на эту статью

Реализация шаблона Dispose, IDisposable и / или финализатора не имеет абсолютно ничего общего с тем, когда память освобождается; вместо этого он имеет прямое отношение к тому, чтобы сообщить сборщику мусора, как вернуть эту память. Когда вы вызываете Dispose (), вы никоим образом не взаимодействуете с GC.

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

Вы можете вызвать GC.Collect (), но на самом деле этого не следует делать, если для этого нет очень веской причины (которая почти всегда «Никогда»). Когда вы форсируете цикл внеполосного сбора, подобный этому, вы фактически заставляете сборщик мусора выполнять больше работы и, в конечном итоге, можете снизить производительность ваших приложений. На время цикла сбора сборщика мусора ваше приложение фактически находится в замороженном состоянии ... чем больше выполняется циклов сборщика мусора, тем больше времени ваше приложение проводит в замороженном состоянии.

Есть также несколько вызовов API-интерфейса Win32, которые вы можете сделать, чтобы освободить рабочий набор, но даже их следует избегать, если для этого нет очень веской причины.

Вся предпосылка, лежащая в основе среды выполнения со сборкой мусора, заключается в том, что вам не нужно беспокоиться (так сильно) о том, когда среда выполнения выделяет / освобождает фактическую память; вам нужно только позаботиться о том, чтобы ваш объект знал, как убирать за собой, когда его об этом просят.

@Keith:

IDisposable предназначен для управляемых ресурсов.

Финализаторы предназначены для неуправляемых ресурсов.

Извините, но это неправильно. Обычно финализатор вообще ничего не делает. Однако, если шаблон удаления был реализован правильно, финализатор пытается вызвать Dispose .

Dispose имеет две работы:

  • Бесплатные неуправляемые ресурсы и
  • бесплатные вложенные управляемые ресурсы.

И здесь ваше утверждение вступает в игру, потому что верно, что во время завершения объект никогда не должен пытаться освободить вложенные управляемые ресурсы, поскольку они, возможно, уже были освобождены. Однако он по-прежнему должен освобождать неуправляемые ресурсы.

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

Ответы на этот вопрос запутались.

Заголовок спрашивает об утилизации, но затем говорит, что они хотят немедленно вернуть память.

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

.Net решает, когда лучше очищать и освобождать память, а не вы, как кодировщик .Net.

Это Dispose способ сообщить .Net, что вы с чем-то закончили, но на самом деле он не освободит память, пока не наступит лучшее время для этого.

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

В .Net вы можете использовать, GC.Collect() чтобы заставить его немедленно, но это почти всегда плохая практика. Если .Net еще не очистил его, значит, сейчас не самое подходящее время для этого.

GC.Collect() подбирает объекты, которые .Net идентифицирует как выполненные. Если вы не удалили объект, который в нем нуждается .Net может решить сохранить этот объект. Это означает, что GC.Collect() это эффективно только в том случае, если вы правильно реализуете свои одноразовые экземпляры.

GC.Collect() это не является заменой для правильного использования IDisposable.

Итак, Dispose и память напрямую не связаны, но и не обязательно. Правильная утилизация сделает ваши .Net-приложения более эффективными и, следовательно, потребляют меньше памяти.


В 99% случаев в .Net рекомендуется следующее:

Правило 1. Если вы не имеете дело с чем-либо неуправляемым или реализуемым IDisposable , не беспокойтесь о Dispose.

Правило 2: если у вас есть локальная переменная, реализующая IDisposable, убедитесь, что вы избавились от нее в текущей области:

//using is best practice
using( SqlConnection con = new SqlConnection("my con str" ) )
{
    //do stuff
} 

//this is what 'using' actually compiles to:
SqlConnection con = new SqlConnection("my con str" ) ;
try
{
    //do stuff
}
finally
{
    con.Dispose();
}

Правило 3. Если у класса есть свойство или переменная-член, реализующая IDisposable, то этот класс также должен реализовывать IDisposable. В методе Dispose этого класса вы также можете удалить свои свойства IDisposable:

//rather basic example
public sealed MyClass :
   IDisposable
{   
    //this connection is disposable
    public SqlConnection MyConnection { get; set; }

    //make sure this gets rid of it too
    public Dispose() 
    {
        //if we still have a connection dispose it
        if( MyConnection != null )
            MyConnection.Dispose();

        //note that the connection might have already been disposed
        //always write disposals so that they can be called again
    }
}

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

Правило 4. Если класс использует неуправляемый ресурс, реализуйте IDispose и добавьте финализатор.

.Net ничего не может сделать с неуправляемым ресурсом, поэтому теперь мы говорим о памяти. Если вы не очистите его, вы можете получить утечку памяти.

Метод Dispose должен иметь дело как с управляемыми, так и с неуправляемыми ресурсами.

Финализатор - это предохранитель: он гарантирует, что, если кто-то другой создаст экземпляр вашего класса и не сможет его удалить, «опасные» неуправляемые ресурсы все равно могут быть очищены с помощью .Net.

~MyClass()
{
    //calls a protected method 
    //the false tells this method
    //not to bother with managed
    //resources
    this.Dispose(false);
}

public void Dispose()
{
    //calls the same method
    //passed true to tell it to
    //clean up managed and unmanaged 
    this.Dispose(true);

    //as dispose has been correctly
    //called we don't need the 

    //'backup' finaliser
    GC.SuppressFinalize(this);
}

Наконец, эта перегрузка Dispose, которая принимает логический флаг:

protected virtual void Dispose(bool disposing)
{
    //check this hasn't been called already
    //remember that Dispose can be called again
    if (!disposed)
    {
        //this is passed true in the regular Dispose
        if (disposing)
        {
            // Dispose managed resources here.
        }

        //both regular Dispose and the finaliser
        //will hit this code
        // Dispose unmanaged resources here.
    }

    disposed = true;
}

Обратите внимание, что как только все это будет сделано, другой управляемый код, создающий экземпляр вашего класса, может просто обрабатывать его, как любой другой IDisposable (Правила 2 и 3).

Я написал сводку по деструкторам и утилизации и сборке мусора на http://codingcraftsman.wordpress.com/2012/04/25/to-dispose-or-not-to-dispose/

Чтобы ответить на исходный вопрос:

  1. Не пытайтесь управлять своей памятью
  2. Dispose - это не управление памятью, а неуправляемое управление ресурсами
  3. Финализаторы являются неотъемлемой частью шаблона Dispose и фактически замедляют освобождение памяти управляемых объектов (поскольку они должны попасть в очередь завершения, если еще не Dispose d)
  4. GC.Collect - это плохо, так как он заставляет некоторые недолговечные объекты казаться необходимыми дольше и таким образом замедляет их сбор.

Однако GC.Collect может быть полезен, если у вас есть критический для производительности раздел кода и вы хотите снизить вероятность его замедления сборкой мусора. Вы называли это раньше.

Вдобавок к этому есть аргумент в пользу этого паттерна:

var myBigObject = new MyBigObject(1);
// something happens
myBigObject = new MyBigObject(2);
// at the above line, there are temporarily two big objects in memory and neither can be collected

против

myBigObject = null; // so it could now be collected
myBigObject = new MyBigObject(2);

Но главный ответ заключается в том, что сборка мусора просто работает, если вы не возитесь с ней!

Отвечая на исходный вопрос, с информацией, предоставленной до сих пор исходным плакатом, можно со 100% уверенностью сказать, что он недостаточно знает о программировании в .NET, чтобы даже получить ответ: используйте GC.Collect (). Я бы сказал, что с вероятностью 99,99% ему вообще не нужно использовать GC.Collect (), как указывалось на большинстве плакатов.

Правильный ответ сводится к следующему: «Пусть сборщик мусора сделает свою работу». Период. Тебе есть о чем беспокоиться. Но вы можете подумать, следует ли и когда удалять или очищать определенные объекты, и нужно ли вам реализовать IDisposable и, возможно, Finalize в своем классе ».

Что касается поста Кита и его правила №4:

Некоторые плакаты путают правило 3 и правило 4. Правило 4 Кита однозначно абсолютно верно. Это одно из четырех правил, которое вообще не требует редактирования. Я бы немного перефразировал некоторые из других его правил, чтобы сделать их более понятными, но они, по сути, верны, если вы правильно их проанализируете и на самом деле прочитаете весь пост, чтобы увидеть, как он расширяет их.

  1. Если ваш класс не использует неуправляемый ресурс И он также никогда не создает экземпляр другого объекта класса, который сам напрямую или в конечном итоге использует неуправляемый объект (то есть класс, который реализует IDisposable), тогда в вашем классе не будет необходимости. либо реализовать сам IDisposable, либо даже вызвать .dispose для чего угодно. (В таком случае глупо думать, что вам действительно НЕОБХОДИМО немедленно освободить память с помощью принудительного сборщика мусора.)

  2. Если ваш класс использует неуправляемый ресурс, ИЛИ создает экземпляр другого объекта, который сам реализует IDisposable, тогда ваш класс должен:

    а) немедленно удалить / освободить их в локальном контексте, в котором они были созданы, ИЛИ ...

    б) реализовать IDisposable по шаблону, рекомендованному в сообщении Кейта, или в нескольких тысячах мест в Интернете, или буквально в 300 книгах.

    b.1) Кроме того, если (b) и это неуправляемый ресурс, который был открыт, ВСЕГДА СЛЕДУЕТ реализовывать как IDisposable, так и Finalize в соответствии с Правилом № 4 Кейта.
    В этом контексте Finalize абсолютно ЯВЛЯЕТСЯ защитной сеткой в ​​одном смысле: если кто-то создает ВАШ объект IDisposable, который использует неуправляемый ресурс, и ему не удается вызвать dispose, то Finalize - это последний шанс для ВАШЕГО объекта правильно закрыть неуправляемый ресурс.
    (Finalize должен сделать это, вызвав Dispose таким образом, чтобы метод Dispose пропускал освобождение чего-либо, НО неуправляемый ресурс. В качестве альтернативы, если метод Dispose вашего объекта вызывается должным образом тем, что создало экземпляр вашего объекта, то он ОБА передает вызов Dispose в все объекты IDisposable, которые он создал, И освобождает неуправляемые ресурсы должным образом, заканчивая вызовом для подавления Finalize для вашего объекта, что означает, что влияние использования Finalize уменьшается, если ваш объект правильно удаляется вызывающим. Все эти моменты включены в сообщение Кита, BTW.)

    b.2) ЕСЛИ ваш класс реализует только IDisposable, потому что он должен по существу передать Dispose объекту IDisposable, который он создал, тогда не реализуйте метод Finalize в своем классе в этом случае. Finalize предназначен для обработки случая, когда ОБА Dispose никогда не вызывался тем, что создало экземпляр вашего объекта, И был использован неуправляемый ресурс, который все еще не выпущен.

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

@ Курт Хагенлохер - все задом наперед. Понятия не имею, почему так много людей проголосовали за это, когда это неправильно.

IDisposable для управляемых ресурсов.

Финализаторы предназначены для неуправляемых ресурсов.

Пока вы используете только управляемые ресурсы, и @Jon Limjap, и я полностью правы.

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

Избегайте использования GC.Collect - это медленный способ работы с управляемыми ресурсами, и он ничего не делает с неуправляемыми, если вы правильно не создали свои ~ Finalizer.


Я удалил комментарий модератора из исходного вопроса в соответствии с https://stackoverflow.com/questions/14593/etiquette-for-modifying-posts

public class MyClass : IDisposable
{
    public void Dispose()
    {
       // cleanup here
    }
}

тогда вы можете сделать что-то вроде этого

MyClass todispose = new MyClass();
todispose.Dispose(); // instance is disposed right here

или

using (MyClass instance = new MyClass())
{

}
// instance will be disposed right here as it goes out of scope

Было бы уместно также упомянуть, что dispose не всегда относится к памяти? Я располагаю ресурсами такие ссылки на файлы чаще, чем на память. GC.Collect () напрямую относится к сборщику мусора CLR и может освобождать или не освобождать память (в диспетчере задач). Скорее всего, это отрицательно скажется на вашем приложении (например, на производительности).

В конце концов, почему вы хотите немедленно вернуть память? Если есть нехватка памяти из-за чего-то еще, ОС в большинстве случаев предоставит вам память.

Если вы не хотите (или не можете) реализовать IDisposable в своем классе, вы можете принудительно выполнить сборку мусора (но это медленно) -

GC.Collect();

Вы не можете заставить GC очищать объект, когда хотите, хотя есть способы заставить его запускаться, ничто не говорит, что он очищает весь объект, который вы хотите / ожидаете. Лучше всего вызывать dispose с помощью метода try catch ex finally dispose end try (VB.NET rulz). Но Dispose предназначен для очистки системных ресурсов (памяти, дескрипторов, подключений к базе данных и т. Д., Выделенных объектом детерминированным образом. Dispose не (и не может) очищать память, используемую самим объектом, только сборщик мусора может это сделать.

Эта статья содержит довольно простое пошаговое руководство. Однако необходимость вызова GC вместо того, чтобы позволить ему идти своим чередом, обычно является признаком плохого дизайна / управления памятью, особенно если не используются ограниченные ресурсы (соединения, дескрипторы, все остальное, что обычно приводит к реализации IDisposable).

Что заставляет вас это делать?

Вы можете удалять только экземпляры, реализующие интерфейс IDisposable.

Чтобы заставить сборщик мусора немедленно освободить (неуправляемую) память:

GC.Collect();  
GC.WaitForPendingFinalizers();

Обычно это плохая практика, но, например, в x64-версии платформы .NET есть ошибка, из-за которой сборщик мусора ведет себя странно в некоторых сценариях, и тогда вы можете захотеть это сделать. Я не знаю, исправлена ​​ли ошибка. Кто-нибудь знает?

Чтобы избавиться от класса, вы делаете это:

instance.Dispose();

или вот так:

using(MyClass instance = new MyClass())
{
    // Your cool code.
}

который будет преобразован во время компиляции в:

MyClass instance = null;    

try
{
    instance = new MyClass();        
    // Your cool code.
}
finally
{
    if(instance != null)
        instance.Dispose();
}

Вы можете реализовать интерфейс IDisposable следующим образом:

public class MyClass : IDisposable
{
    private bool disposed;

    /// <summary>
    /// Construction
    /// </summary>
    public MyClass()
    {
    }

    /// <summary>
    /// Destructor
    /// </summary>
    ~MyClass()
    {
        this.Dispose(false);
    }

    /// <summary>
    /// The dispose method that implements IDisposable.
    /// </summary>
    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// The virtual dispose method that allows
    /// classes inherithed from this one to dispose their resources.
    /// </summary>
    /// <param name="disposing"></param>
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Dispose managed resources here.
            }

            // Dispose unmanaged resources here.
        }

        disposed = true;
    }
}

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

У вас может быть детерминированное уничтожение объекта в c ++

Вы никогда не захотите вызывать GC.Collect, он мешает самонастройке сборщика мусора для обнаружения нехватки памяти и в некоторых случаях ничего не делает, кроме увеличения текущего поколения каждого объекта в куче.

Для тех, кто публикует ответы на IDisposable. Вызов метода Dispose не уничтожает объект, как описывает спрашивающий.

Извините, но выбранный здесь ответ неверен. Как впоследствии заявили несколько человек, Dispose, и реализация IDisposable не имеет ничего общего с освобождением памяти, связанной с классом .NET. Он в основном и традиционно используется для освобождения неуправляемых ресурсов, таких как дескрипторы файлов и т. Д.

Хотя ваше приложение может вызвать GC.Collect (), чтобы попытаться принудительно выполнить сборку сборщиком мусора, это действительно повлияет только на те элементы, которые находятся на правильном уровне генерации в очереди freachable. Таким образом, возможно, что если вы очистили все ссылки на объект, это может быть несколько вызовов GC.Collect (), прежде чем фактическая память будет освобождена.

Вы не говорите в своем вопросе, ПОЧЕМУ вы чувствуете необходимость немедленно освободить память. Я понимаю, что иногда могут быть необычные обстоятельства, но серьезно, в управляемом коде почти всегда лучше позволить среде выполнения заниматься управлением памятью.

Вероятно, лучший совет, если вы думаете, что ваш код использует память быстрее, чем GC освобождает ее, тогда вам следует просмотреть свой код, чтобы убедиться, что никакие объекты, которые больше не нужны, не упоминаются в каких-либо структурах данных, которые у вас лежат в статических членах и т. Д. Также старайтесь избегать ситуаций, когда у вас есть циклические ссылки на объекты, поскольку есть вероятность, что они также не могут быть освобождены.

Конрад Рудольф - да, обычно финализатор вообще ничего не делает. Вы не должны реализовывать его, если не имеете дело с неуправляемыми ресурсами.

Затем, когда вы его реализуете, вы используете шаблон удаления Microsoft (как уже описано)

  • public Dispose()звонки protected Dispose(true)- работают как с управляемыми, так и с неуправляемыми ресурсами. Вызов Dispose()должен подавлять завершение.

  • ~Finalizeзвонки protected Dispose(false)- работает только с неуправляемыми ресурсами. Это предотвращает утечки неуправляемой памяти, если вы не вызоветеpublic Dispose()

~Finalize работает медленно и не должен использоваться, если у вас нет неуправляемых ресурсов.

Управляемые ресурсы не могут иметь утечку памяти, они могут тратить ресурсы только на текущее приложение и замедлять его сборку мусора. Неуправляемые ресурсы могут протекать, и ~Finalize лучше всего гарантировать, что они этого не сделают.

В любом случае using это лучшая практика.

Полное объяснение Джо Даффи на тему « Удаление, завершение и управление ресурсами »:

Раньше в период существования .NET Framework финализаторы постоянно назывались деструкторами программистами на C#. По мере того, как мы со временем становимся умнее, мы пытаемся смириться с тем фактом, что метод Dispose на самом деле более эквивалентен деструктору C++ (детерминированный) , в то время как финализатор является чем-то совершенно отдельным (недетерминированным) . Тот факт, что C# заимствовал синтаксис деструктора C++ (т.е. ~ T ()), несомненно, имел хоть какое-то отношение к развитию этого неправильного названия.

@Keith,

Я согласен со всеми вашими правилами кроме №4. Добавление финализатора должно выполняться только при очень определенных обстоятельствах. Если класс использует неуправляемые ресурсы, их следует очистить с помощью функции Dispose (bool). Эта же функция должна очищать управляемые ресурсы только тогда, когда bool имеет значение true. Добавление финализатора увеличивает сложность использования вашего объекта, поскольку каждый раз, когда вы создаете новый экземпляр, он также должен быть помещен в очередь финализации, которая проверяется каждый раз, когда GC запускает цикл сбора. Фактически это означает, что ваш объект выживает на один цикл / поколение дольше, чем должен, поэтому финализатор может быть запущен. Финализатор не следует рассматривать как «страховочную сетку».

Сборщик мусора будет запускать цикл сбора только в том случае, если он определит, что в куче Gen0 недостаточно доступной памяти для выполнения следующего выделения, если только вы не «поможете» ему, вызвав GC.Collect () для принудительного внеполосного сбора. .

Суть в том, что, несмотря ни на что, GC знает только, как освободить ресурсы, вызвав метод Dispose (и, возможно, финализатор, если он реализован). Этот метод должен «делать правильные вещи» и очищать все используемые неуправляемые ресурсы и давать указание любым другим управляемым ресурсам вызывать их метод Dispose. Он очень эффективен в том, что делает, и может в значительной степени самооптимизироваться, если ему не помогают внеполосные циклы сбора данных. При этом, за исключением явного вызова GC.Collect, у вас нет контроля над тем, когда и в каком порядке будут удаляться объекты и освобождаться память.