Переменные с областью действия функции

#c# #exception-handling #garbage-collection

#c# #исключение #сборка мусора

Вопрос:

Как среда CLR обрабатывает локальные переменные с областью действия функции в случае возникновения исключения. обязательно ли использовать блок finally или переменная удаляется, как только поток покидает функцию

ниже приведен небольшой пример

     protected void FunctionX()
    {
        List<Employee> lstEmployees;
        try
        {
           lstEmployees= new List<Employee>();
           int s =  lstEmployees[1].ID; // code intended to throw exception
        }
        catch (Exception ex)
        {
            ManageException(ex, ShowMessage); //exception is thrown here
        }
        finally { lstEmployees= null; } // Is the finally block required to make sure the list is cleaned
    }
  

Ответ №1:

Чтобы ответить на ваш конкретный вопрос, нет, finally указанный вами блок не требуется.

Присвоение null ссылочной переменной фактически ничего не делает, поскольку сборка мусора недетерминирована. В качестве упрощенного объяснения, время от времени сборщик мусора проверяет объекты в куче, чтобы определить, есть ли какие-либо активные ссылки на них (это называется «внедрением»). Если нет активных ссылок, то эти ссылки подходят для сборки мусора.

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

Есть определенные типы (оба внутри .NET и в библиотеках сторонних производителей), которые реализуют IDisposable интерфейс и предоставляют некоторые детерминированные процедуры очистки с помощью Dispose() функции. При использовании этих типов вы должны всегда вызывать Dispose() , когда закончите с типом. В случаях, когда время жизни экземпляра не должно превышать время жизни функции, вы можете использовать using() { } блок, но это требуется только в том случае, если тип реализует, IDisposable что List<T> (как вы использовали в своем примере) не выполняется.

Комментарии:

1. Также интересно отметить, что GC может быть довольно агрессивным. Он может собирать память для экземпляра, даже если вы не установили для него значение null, при условии, что компилятор / jitter определил, что ссылка больше не будет использоваться. Это относится даже к методам в экземпляре, поэтому, если у вас есть метод в классе, и этот метод является последним методом, который вы когда-либо вызывали в этом экземпляре, экземпляр может быть собран, как только метод перестанет использовать ‘this’.

2. @Dan: Точно; отличные примеры.

Ответ №2:

Не беспокойтесь об очистке объектов, вот почему .NET и большинство современных языков предоставляют функциональность сборки мусора во время выполнения.

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

Ответ №3:

Некоторые другие ответы здесь слегка вводят в заблуждение.

На самом деле, сборщик мусора не имеет (почти) никакого отношения к переменной lstEmployees . Но ему никогда не нужно устанавливать значение null , ни в обычном потоке кода, ни после возникновения исключения.

Установка ссылок на null для освобождения объекта, на который они указывают, почти никогда не требуется, особенно для локальных объектов.

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

С другой стороны, неуправляемые ресурсы, которые не обрабатываются CG, всегда требуют ручной очистки (через Dispose метод IDisposable интерфейса). Чтобы убедиться, что такие ресурсы возвращаются после возникновения исключения, вам действительно нужно finally предложение. Или, если вы не собираетесь обрабатывать исключение локально, вы можете заменить try … finally на using предложение:

 using (someUnmanagedResource) {
    // … use the resource …
}
// Will implicitly call someUnmanagedResource.Dispose() *whatever happens*!
  

Комментарии:

1. Что насчет моего ответа вводит в заблуждение …?

2. @Adam Я мог бы поклясться, что в вашем ответе говорилось о том, как GC обрабатывает finally здесь. Ваш ответ прекрасен. Другие ответы либо подразумевают это, либо не упоминают, что finally здесь не делает ничего особенного и что null присваивание здесь в любом случае не требуется.

Ответ №4:

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

Ответ №5:

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

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

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

Комментарии:

1. Просто для ясности, вызов Dispose() объекта, который реализует IDisposable , не является выбором того, хотите ли вы, чтобы GC его очистил, или если вы хотите, чтобы он был очищен явно. Шаблон вокруг IDisposable гласит, что вы обязаны вызывать Dispose() , когда экземпляр больше не нужен.

2. @Adam Robinson — Вы правы, я не смог правильно это объяснить. Я просто пытался отметить, что если вам нужно очистить ресурсы и вы не хотите ждать, пока GC вызовет ваш объектный финализатор, вы можете реализовать шаблон интерфейса IDisposable. Спасибо за разъяснение!

Ответ №6:

Сборщик мусора .NET обработает это за вас. Фактически, установка «lastEmployees» в значение null выполняет то же самое, что и простой выход из функции.

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

В .NET вам никогда не нужно беспокоиться об очистке управляемого ресурса. Следовательно, управляемый.

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