Как я удостоверяюсь, что от объектов избавляются правильно в.NET?

Вы используете шаблон начальной загрузки Start Bootstrap - Clean Blog v5.0.2, создатель этого шаблона добавил margin-bottom: 50px к тегу <header>. если вы измените этот тег на другой элемент, такой как <div>, проблема будет решена.

7
задан Peter Mortensen 10 January 2010 в 17:12
поделиться

7 ответов

Лучше всего убедиться, что все объекты, реализующие интерфейс IDisposable , вызываются Dispose, как только объект больше не требуется.

Это может быть выполнено. либо с помощью ключевого слова using , либо конструкций try / finally .

Внутри формы WinForms, ресурсы которой выделены на время ее существования, необходим несколько иной подход. Поскольку сама форма реализует IDisposable, это означает, что в какой-то момент в этой форме будет вызываться Dispose. Вы хотите убедиться, что ваши одноразовые ресурсы утилизируются одновременно. Для этого вы должны переопределить метод forms Dispose (bool dispose) . Реализация должна выглядеть примерно так:

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        // dispose managed resources here
    }
    // dispose unmanaged resources here
}

Примечание о компонентах в формах: если ваш объект реализует интерфейс IComponent , вы можете поместить экземпляр в формы Контейнер . Контейнер позаботится об утилизации компонентов, когда сам контейнер будет утилизирован.

14
ответ дан 6 December 2019 в 07:08
поделиться

Когда объект недоступен, вызывается метод Object.Finalize . Полезно подавить этот ненужный вызов в ваших классах, которые реализуют IDisposable. Вы можете сделать это, вызвав метод GC.SuppressFinalize

public void Dispose()
{
    // dispose resources here

    GC.SuppressFinalize(this);
}
1
ответ дан 6 December 2019 в 07:08
поделиться

There are a few ways of ensuring this. The main help I find is by utilising the "using" keyword. This is applied as such:

using(SqlConnection connection = new SqlConnection(myConnectionString))
{
    /* utilise the connection here */ 
}

This basically translates into:

SqlConnection connection = null;
try
{
    connection = new SqlConnection(myConnectionString);
}
finally
{
    if(connection != null) connection.Dispose();
}

As such it only works with types that implement IDisposable.

This keyword is massively useful when dealing with GDI objects such as pens and brushes. However there are scenarios where you will want to hold onto resources for a longer period of time than just the current scope of a method. As a rule it's best to avoid this if possible but for example when dealing with SqlCe it's more performant to keep one connection to the db continuously open. Therefore one can't escape this need.

In this scenario you can't use the "using" but you still want to be able to easily reclaim the resources held by the connection. Есть два механизма, которые вы можете использовать, чтобы вернуть эти ресурсы.

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

public class MyClassThatHoldsResources
{
    private Brush myBrush;

    // this is a finaliser
    ~MyClassThatHoldsResources()
    {
       if(myBrush != null) myBrush.Dispose();
    }
}

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

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

class MySerialPortAccessor
{
    private SerialPort m_Port;

    public MySerialPortAccessor(string port)
    {
        m_Port = new SerialPort(port);
        m_Port.Open();
    }

    ~MySerialPortAccessor()
    {
        if(m_Port != null) m_Port.Dispose();
    }
}

Тогда, если бы я использовал объект следующим образом:

public static void Main()
{
    Test1();
    Test2();
}

private static void Test1()
{
    MySerialPortAccessor port = new MySerialPortAccessor("COM1:");
    // do stuff
}

private static void Test2()
{
    MySerialPortAccessor port = new MySerialPortAccessor("COM1:");
    // do stuff
}

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

Поэтому я действительно хочу сделать следующее:

class MySerialPortAccessor : IDispable
{
    private SerialPort m_Port;

    public MySerialPortAccessor(string port)
    {
        m_Port = new SerialPort(port);
        m_Port.Open();
    }

    public void Dispose()
    {
        if(m_Port != null) m_Port.Dispose();
    }
}

И я перепишу свой тест следующим образом:

public static void Main()
{
    Test1();
    Test2();
}

private static void Test1()
{
    using( MySerialPortAccessor port = new MySerialPortAccessor("COM1:"))
    {
        // do stuff
    }
}

private static void Test2()
{
    using( MySerialPortAccessor port = new MySerialPortAccessor("COM1:"))
    {
        // do stuff
    }
}

сейчас будет работать. Так что из финализатора? Зачем его использовать?

Неуправляемые ресурсы и возможные реализации, которые не вызывают Dispose.

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

В заключение, шаблон, рекомендованный в книге .NET Framework Guidelines , должен реализовать оба варианта следующим образом:

public void SomeResourceHoggingClass, IDisposable
{
    ~SomeResourceHoggingClass()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
    }

    // virtual so a sub class can override it and add its own stuff
    //
    protected virtual void Dispose(bool deterministicDispose)
    {    
         // we can tidy managed objects
         if(deterministicDispose)
         {
              someManagedObject.Parent.Dispose();
              someManagedObject.Dispose();
         }

         DisposeUnmanagedResources();

         // if we've been disposed by .Dispose()
         // then we can tell the GC that it doesn't
         // need to finalise this object (which saves it some time)
         //
         GC.SuppressFinalize(this);
    }
}
2
ответ дан 6 December 2019 в 07:08
поделиться

В дополнение к тому, что уже было сказано, если вы используете COM-компоненты, очень хорошая идея, чтобы убедиться, что они полностью освобождены. У меня есть фрагмент, который я все время использую для COM-релизов:

private void ReleaseCOMObject(object o)
{
   Int32 countDown = 1;
   while(countDown > 0)
       countDown = System.Runtime.InteropServices.Marshal.ReleaseCOMObject(o);
}
4
ответ дан 6 December 2019 в 07:08
поделиться

Несколько советов:

-Используйте ключевое слово Using (), когда сможете. Если у вас есть модульные тесты, я бы порекомендовал рефакторинг вашего кода для реализации этого изменения.

http://msdn.microsoft.com/en-us/library/yh598w02.aspx

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

1
ответ дан 6 December 2019 в 07:08
поделиться

Что касается мониторинга встроенного perfmon ( 2 ), то он отлично работает для использования памяти и т. Д. Если вы беспокоитесь о дескрипторах файлов, дескрипторы dll и т. д. Я рекомендую Process Explorer и Process Monitor

1
ответ дан 6 December 2019 в 07:08
поделиться

Вам следует позвонить Dispose , чтобы узнать о дефицитных ресурсах, чтобы освободить их. В этом случае вы можете использовать оператор using :

using (var resource = new MyScarceObject()) 
{
    // resource will be used here...
} // will free up the resources by calling Dispose automatically
2
ответ дан 6 December 2019 в 07:08
поделиться