#c# #.net #memory-management #object-lifetime
#c# #.net #управление памятью #срок службы объекта
Вопрос:
После окончания блока
{
}
Что происходит с переменной, находящейся в блоке?
{
int a;
a=2;
int b = 3;
}
//What happened now???
и что происходит после этого блока
{
int a=2;
int b = 3;
}
GC.Collect();
Это понятно?
Если теги, которые я выбрал, неверны, пожалуйста, отредактируйте их или, если вы можете отредактировать мой вопрос, чтобы было понятно, пожалуйста, отредактируйте его.
Ответ №1:
В конце блока все переменные, объявленные внутри, просто «выходят за пределы области видимости».
Скорее всего, они удалены из стека, но детали доступны оптимизаторам.
И поскольку все переменные вашего примера являются int
s (ValueTypes), они не имеют никакого отношения к сборке мусора.
Если мы изменим последний пример на:
{
int a=2;
var b = new StringBuilder();
...
}
GC.Collect();
Затем память для StringBuilder будет собрана в GC.Collect(). Обратите внимание, что обычной программе никогда не нужно вызывать GC.Collect().
Комментарии:
1. Если бы они были массивами int или list , что теперь?
2. Если b является списком / массивом
int
, он обрабатывается как StringBuilder.3. Вам никогда не придется заставлять ее, она будет выполняться при необходимости. Не всегда после каждого блока.
4. GC использует несколько факторов, наиболее важных: нехватка памяти. Существуют разные версии GC с разным поведением.
5. Если вы хотите узнать: msdn.microsoft.com/en-us/magazine/bb985010.aspx , msdn.microsoft.com/en-us/magazine/bb985011.aspx
Ответ №2:
Ссылочные переменные внутри блока выйдут из области видимости. Помеченные сборкой мусора, они останутся помеченными, поскольку на них больше нет ссылок. Поскольку у вас нет никаких ссылочных переменных, GC не будет задействован.
В определенный момент запустится сборщик мусора и решит, можно ли очистить память, используемую ссылочными переменными. Это зависит от того, в каком поколении они находятся, поэтому они могут быть удалены не сразу.
Вызов GC.Collect();
просто заставляет GC запускаться, хотя сбор не определен. Это, для большинства приложений, не требуется.
Комментарии:
1. Я знаю, что такое GC. Collect() выполняет.
2. @LightWing — Вы знаете, но не все, кто читает вопрос, знают. В любом случае — вы не дали понять, что знаете.
3. 1) Сборка мусора не применяется к таким типам значений, как
int
. 2) Точка, в которой происходит сборка мусора, является какой угодно, но не «определенной». В этом действительно весь смысл.4. Ссылки не «помечаются для сбора», когда их переменные выходят за пределы области видимости . Вы неправильно понимаете, как работает фаза «пометки» сборщика пометок и развертки, если вы думаете, что так оно и работает, или вы неправильно в это верите. NET использует семантику коллекции с подсчетом ссылок. Скорее, при выполнении GC все объекты помечаются для удаления, а затем при транзитивном закрытии заведомо живых объектов их метки удаляются. Все объекты, которые остаются помеченными, удаляются. (Или перемещается в очередь финализатора.)
Ответ №3:
В конце блока переменные, которые были объявлены внутри блока, выходят за пределы области видимости. Если это типы значений (например, int), они просто удаляются из стека. Если они являются ссылочными типами (как, например, большинство других объектов StringBuilder
), то на них больше не будет ссылаться что-либо (если только вы не передали это чему-либо за пределами блока, который все еще находится в области видимости), и сборщик мусора получит это когда-нибудь позже.
Если у вас есть объекты, которые обращаются к ограниченным ресурсам, таким как различные Stream
классы на основе (или что-либо, что реализует IDisposable
), вы должны поместить это в оператор using, подобный этому:
using (Stream s = GetStream())
{
// Do something with the stream.
}
В конце блока using вызывается Dispose
метод и освобождаются любые ресурсы (такие как обработчики файлов, подключения к базе данных, большие куски памяти и т.д.)
В общем случае вам не нужно понимать, когда именно запустится сборщик мусора или освободится память. Мне было труднее всего понять это еще тогда, когда я перешел с C на .NET в 2002 году просто потому, что я так привык вызывать delete
любой объект, который я создал в куче.
Вам больше не нужно беспокоиться ни о чем из этого. Даже если вы забудете вызвать dispose, сборщик мусора рано или поздно доберется до нее (хотя вы, вероятно, не хотите хранить этот дескриптор файла дольше, чем необходимо, следовательно IDisposable
)