Net framework 5, а также среды Visual Studio 2012 и C#



Download 6,27 Mb.
Pdf ko'rish
bet410/658
Sana12.06.2023
Hajmi6,27 Mb.
#950840
1   ...   406   407   408   409   410   411   412   413   ...   658
Bog'liq
CLR via C Programmirovanie na platforme Microsoft NET Framework 4 5 na yazyke C

рис. 21.3.
.Управляемая.куча.после.уборки.мусора
Если CLR не удается освободить память в результате уборки мусора, а в про-
цессах не осталось адресного пространства для выделения нового сегмента, значит, 
свободная память процесса полностью исчерпана. В этом случае попытка выделения 
новой памяти оператором 
new
приведен к выдаче исключения 
OutOfMemoryExcep-
tion
. Ваше приложение может перехватить это исключение и восстановиться после 
него, но большинство приложений не пытается это делать; вместо этого исключение 
превращается в необработанное, Windows завершает процесс, а затем освобождает 
всю память, использованную процессом.
Программист должен извлечь для себя несколько важных уроков из этого опи-
сания. Во-первых, исключается утечка объектов, так как все объекты, недоступные 
от корней приложения, рано или поздно уничтожает уборщик мусора. Во-вторых, 
благодаря уборке мусора невозможно получить доступ к освобожденному объекту 
с последующим повреждением памяти.
ВниМание
Статическое.поле.типа.хранит.объект,.на.который.ссылается,.бессрочно.или.до.
выгрузки.домена.приложений.с.загруженными.типами .Чаще.всего.утечка.памяти.
возникает.из-за.хранения.в.статическом.поле.ссылки.на.коллекцию,.в.которую.
добавляются.элементы .Статическое.поле.сохраняет.объект.коллекции,.которая,.
в.свою.очередь,.сохраняет.все.свои.элементы .Поэтому.статических.полей.следует.
по.возможности.избегать 


560
Глава.21 .Автоматическое.управление.памятью.(уборка.мусора)
Уборка мусора и отладка
Как только объект становится недостижимым, он превращается в кандидата на 
удаление — объекты далеко не всегда «доживают» до завершения работы метода. 
Для приложения эта особенность может иметь интересные последствия. Например, 
рассмотрим следующий код:
using System;
using System.Threading;
public static class Program {
public static void Main() {
// Создание объекта Timer, вызывающего метод TimerCallback
// каждые 2000 миллисекунд
Timer t = new Timer(TimerCallback, null, 0, 2000);
// Ждем, когда пользователь нажмет Enter
Console.ReadLine();
}
private static void TimerCallback(Object o) {
// Вывод даты/времени вызова этого метода
Console.WriteLine("In TimerCallback: " + DateTime.Now);
// Принудительный вызов уборщика мусора в этой программе
GC.Collect();
}
}
Откомпилируйте этот код из командной строки, не используя никаких специ-
альных параметров компилятора. Затем, запустив полученный исполняемый файл, 
вы увидите, что метод 
TimerCallback
вызывается всего один раз!
После изучения приведенного кода складывается впечатление, что метод 
TimerCallback
будет вызываться каждые 2000 миллисекунд. В конце концов, мы 
создаем объект 
Timer
, на который ссылается переменная 
t
. Поскольку таймер суще-
ствует, он должен срабатывать. Но обратите внимание, что в методе 
TimerCallback
процедура уборки мусора вызывается принудительно методом 
GC.Collect()
.
После запуска уборщик мусора предполагает, что все объекты в куче недостижи-
мы (то есть являются мусором), в том числе объект 
Timer
. Затем уборщик проверяет 
корни приложения и видит, что метод 
Main
не использует переменную 
t
после 
присвоения ей значения. Поэтому в приложении нет переменной, ссылающейся на 
объект 
Timer
, и уборщик мусора освобождает занятую им память. В итоге таймер 
останавливается, а метод 
TimerCallback
вызывается всего один раз.
Допустим, вы используете отладчик для метода 
Main
, а уборка мусора происходит 
сразу после присвоения переменной 
t
адреса нового объекта 
Timer
. Что случится, 
если затем вы попытаетесь просмотреть объект, на который ссылается 
t
, в окне 
Quick.Watch
отладчика? Отладчик не сможет показать объект, потому что тот был 
удален уборщиком мусора. Для многих разработчиков такой вариант развития 


561
Управляемая.куча
событий стал бы очень неприятным сюрпризом, поэтому специалисты Microsoft 
предложили другое решение.
При компиляции сборки с ключом 
/debug
компилятора C# компилятор при-
меняет к полученной сборке атрибут 
System.Diagnostics.DebuggableAttribute
с установленным флагом 
DisableOptimizations
. При компиляции метода во 
время выполнения JIT-компилятор видит, что этот атрибут задан, и искусственно 
продлевает время жизни всех корней до завершения метода. В моем примере JIT-
компилятор считает, что переменная 
t
в 
Main
должна существовать до конца метода. 
Таким образом, если происходит уборка мусора, уборщик теперь считает, что 
t
остается корнем, а объект 
Timer
, на который ссылается 
t
, по-прежнему достижим. 
Объект 
Timer
переживет уборку мусора, а метод 
TimerCallback
будет вызываться 
многократно вплоть до выхода из 
Main
.
Чтобы убедиться в этом, перекомпилируйте программу из командной строки, 
но на этот раз укажите ключ компилятора C# 
/debug
. Теперь при выполнении 
полученного исполняемого файла метод 
TimerCallback
будет вызываться много-
кратно! Учтите, что ключ 
/optimize+
компилятора C# снова включает оптимизации, 
поэтому он не должен использоваться при проведении эксперимента.
JIT-компилятор делает это, чтобы помочь вам в процессе отладки. Теперь мож-
но запустить приложение в обычном режиме (без отладчика), и если метод будет 
вызван, JIT-компилятор искусственно увеличит время жизни переменных до его 
окончания. Затем, если к процессу будет добавлен отладчик, можно вставить точку 
останова в ранее скомпилированный метод и изучить переменные.
Теперь вы знаете, как создать программу, которая работает в отладочном вари-
анте, но не работает должным образом в готовой версии. Но программа, корректно 
работающая только в режиме отладки, бесполезна. Поэтому необходимо средство, 
обеспечивающее работу программы независимо от типа ее сборки.
Можно попробовать изменить метод 
Main
следующим образом:
public static void Main() {
// Создание объекта Timer, вызывающего метод TimerCallback каждые 2000 мс
Timer t = new Timer(TimerCallback, null, 0, 2000);
// Ждем, когда пользователь нажмет Enter
Console.ReadLine();
// Создаем ссылку на t после ReadLine
// (в ходе оптимизации эта строка удаляется)
t = null;
}
Все равно после компиляции этого кода (без параметра 
/debug+
) и запуска полу-
ченного исполняемого файла (без отладчика) выяснится, что метод 
Timer_Callback
вызывается всего раз. Дело здесь в том, что JIT-компилятор является оптимизиру-
ющим, а приравнивание локальной переменной или переменной-параметра к 
null
равнозначно отсутствию ссылки на эту переменную. Иначе говоря, JIT-компилятор 
в ходе оптимизации полностью убирает строку 
t = null;
из программы, из-за 


562
Download 6,27 Mb.

Do'stlaringiz bilan baham:
1   ...   406   407   408   409   410   411   412   413   ...   658




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©hozir.org 2024
ma'muriyatiga murojaat qiling

kiriting | ro'yxatdan o'tish
    Bosh sahifa
юртда тантана
Боғда битган
Бугун юртда
Эшитганлар жилманглар
Эшитмадим деманглар
битган бодомлар
Yangiariq tumani
qitish marakazi
Raqamli texnologiyalar
ilishida muhokamadan
tasdiqqa tavsiya
tavsiya etilgan
iqtisodiyot kafedrasi
steiermarkischen landesregierung
asarlaringizni yuboring
o'zingizning asarlaringizni
Iltimos faqat
faqat o'zingizning
steierm rkischen
landesregierung fachabteilung
rkischen landesregierung
hamshira loyihasi
loyihasi mavsum
faolyatining oqibatlari
asosiy adabiyotlar
fakulteti ahborot
ahborot havfsizligi
havfsizligi kafedrasi
fanidan bo’yicha
fakulteti iqtisodiyot
boshqaruv fakulteti
chiqarishda boshqaruv
ishlab chiqarishda
iqtisodiyot fakultet
multiservis tarmoqlari
fanidan asosiy
Uzbek fanidan
mavzulari potok
asosidagi multiservis
'aliyyil a'ziym
billahil 'aliyyil
illaa billahil
quvvata illaa
falah' deganida
Kompyuter savodxonligi
bo’yicha mustaqil
'alal falah'
Hayya 'alal
'alas soloh
Hayya 'alas
mavsum boyicha


yuklab olish