Как расположить класс в .net?

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

MyClass.Dispose()

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

15.08.2008 15:26:41
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.

101
2.09.2008 01:44:45
Я просто хотел отметить, что с этим вопросом и его ответами есть проблема терминологии. Вы все говорите об освобождении / утилизации объектов; т.е. экземпляры класса. Класс - это сам тип, связанный с ним код - процедуры, функции, свойства и т. Д. - и данные общего (статического) класса. Освобождение памяти или других ресурсов из самого класса намного сложнее, чем у экземпляра, так как включает в себя выгрузку всего AppDomain, в котором живет класс, а также его сборки и других связанных классов. Конечно, это не то, что обычно хочется делать.
Guillermo Prandi 22.09.2015 01:12:53
@Curl, было бы хорошо, если бы вы включили несколько примеров кода.
T.Todua 28.09.2017 15:01:11

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

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

1
15.08.2008 15:34:43
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
3
15.08.2008 15:32:02

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

MyClass.Dispose();

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

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

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

0
15.08.2008 15:32:40

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

GC.Collect();
0
15.08.2008 15:33:55

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

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

14
15.08.2008 15:41:02

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

2
15.08.2008 15:42:36

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

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

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

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

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

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;
    }
}
23
26.08.2008 09:31:11
Это то, что я пытаюсь решить. Если у вас есть код, MyClassкоторый вы хотите указать, с которым вы сделали. Вы просто назначаете как ноль? что вы говорите, то же самое, что реализация IDisposable? Нелегко объяснить, что я пытаюсь спросить. По сути, у меня есть цикл, который сообщает о классе в каждом цикле, и я хочу указать, что с ним покончено. Я оставляю это как есть или назначаю нуль, или реализую это. uisngоператор без всех других битов (финализатор). пустой метод утилизации. Или это неправильно.
Seabizkit 6.08.2017 08:15:31
@Seabizkit, вы должны реализовывать IDisposable только в том случае, если ваш класс держится за другие вещи, которые IDisposable (и вызывают их метод Dispose), и когда вы используете такие вещи, как неуправляемые ресурсы. Если вы беспокоитесь о стоимости GC в цикле, возможно, вам следует подумать о том, чтобы сделать его типом значения (структурой) или каким-то образом повторно использовать экземпляр, изменив его работу.
Patrik Svensson 7.08.2017 02:41:11

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

0
15.08.2008 16:48:49

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

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

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

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

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

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

6
24.08.2011 09:53:31

Вы можете иметь детерминированное уничтожение объектов в C ++

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

Для тех, кто публикует идентифицируемые ответы. Вызов метода Dispose не уничтожает объект, как описывает Аскер.

0
25.08.2008 21:18:25

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

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

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

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

1
25.08.2008 21:29:10

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

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

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

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

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

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


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

0
23.05.2017 12:02:02

@Keith:

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

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

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

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

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

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

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

0
26.08.2008 09:11:17

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

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

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

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

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

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

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

0
28.08.2008 16:06:28

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

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

3
26.08.2008 09:36:18

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

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

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

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

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

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

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

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

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

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


99% времени в .Net следующие лучшие практики:

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

Правило 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).

19
1.09.2008 09:09:20

@Keith,

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

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

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

1
31.08.2008 10:26:30

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

Правильный ответ сводится к следующему: «Пусть GC сделает свою работу. Период. У вас есть другие вещи, чтобы беспокоиться о. Но вы, возможно, захотите подумать, следует ли вам и когда удалять или очищать определенные объекты, и нужно ли вам реализовать 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 уменьшается, если вызывающий объект должным образом расположен. включены в сообщение Кита, кстати.)

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

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

0
23.03.2012 01:25:58
Спасибо за то, что указал на то, что я недостаточно знаю о программировании в .Net, и поэтому не должен давать ответа (даже без учета подачи стека overoverflow, пока он еще запускался)! Я полагаю, это было поздно ночью, когда вы написали ответ, и обычно дела идут лучше.
Jorrit Reedijk 9.05.2012 21:40:03
@Jorrit Ваше имя также Джон Галлоуэй или OP?
Jaycephus 16.10.2018 21:44:37

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

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

  1. Не пытайтесь управлять своей памятью
  2. Dispose - это не управление памятью, а управление неуправляемыми ресурсами.
  3. Финализаторы являются врожденной частью шаблона Dispose и фактически замедляют освобождение памяти управляемых объектов (так как они должны идти в очередь Finalization, если только не 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);

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

3
2.05.2012 22:13:37