
- •Эволюция методологий программирования. Парадигмы программирования.
- •III семестр
- •Основные определения.
- •IV семестр (ответы на вопросы к экзамену по java freebrain.Ru)
- •1. Виртуальная машина Java. Структура программ. Типы переменных в Java. Принципы работы ClassLoader.
- •2. Средства абстракции Java
- •3. Внутренние и вложенные классы Java
- •4. Средства инкапсуляции Java. Поддержка модульности. Пакеты
- •5. Иерархические отношения в Java
- •6. Агрегация и зависимость от времени жизни. Реализация отношений клиент-сервер. Стандартные контейнеры.
- •7. Типизация. Правила преобразования типов. Instanceof и ClassCastException. Класс Class.
- •8. Средства поддержки параллелизма. Активные и пассивные объекты. Класс Object
- •9. Использование Thread и Runnable. Пул потоков, назначение и принципы реализации
- •10. Исключения. Обработка исключительных ситуаций
- •11. Сохраняемость. Serializable и Externalizable. Программирование распределенных приложений
- •12. Модель безопасности Java. Policy, Permissions, AccessController
- •14. Средства поддержки Java машины. System, Runtime, сборка мусора
14. Средства поддержки Java машины. System, Runtime, сборка мусора
Поддержкой языка и платформы Java явл-ся пакет java.lang. В нем хранятся базовые функции языка, и весь этот пакет автоматически импортируется транслятором во все программы. Классы java.lang.System и java.lang.Runtime обеспечивают программе своего рода доступ во «внешний мир»: в первом можно найти статические переменные содержащие ссылки на стандартные потоки ввода, вывода и ошибок, а также методы для работы со стандартными свойствами (настройками) java машины, методы взятия текущего времени в миллисекундах с момента 00 часов 1 января 1970 года, exit() - прекращение работы виртуальной машины и завершение процесса, gc() - Принудительный вызов сборщика мусора,методы для манипуляции с загружаемыми native библиотеками (dll , ld.so). В классе Runtime можно найти семейство вызовов для запуска отдельного процесса (программы) в операционной системе, методы exit(int status), halt() - Shutdown и остановка java машины, методы для получения информации о доступной памяти, методы установки и удаления перехватчиков, вызываемых при остановке виртуальной машины, методы запуска сборщика мусора и финализатора и т.д.
Сборщик мусора, основанный на поколениях, делит динамическую память на несколько поколений. Объекты создаются в молодом поколении, а объекты, отвечающие некоторым критериям продвижения, например, они пережили определенное число сборок мусора, затем переводятся в более старшее поколение. Сборщик мусора, основанный на поколениях, свободно может применять различные стратегии для разных поколений и раздельно производить сборку мусора для разных поколений.
Одно из преимуществ сборки мусора на основе поколений заключается в том, что она может сократить паузы, не обрабатывая все поколения сразу. Если распределитель ресурсов не способен выполнить запросы на размещение, то он сначала запускает вспомогательные сборки мусора, которые обрабатывают только самое младшее поколение. Так как многие объекты в молодом поколении будут уже мертвы, а копирующему сборщику мусора совсем не надо проверять мертвые объекты, то паузы на вспомогательные сборки мусора могут быть достаточно малыми, и зачастую могут возвращать значительный объем динамической памяти. Если вспомогательная сборка мусора освобождает достаточно места в динамической памяти, то пользовательская программа может немедленно возобновить работу. Если же она освобождает недостаточно места в динамической памяти, то сборка продолжится в более старших поколениях до тех пор, пока не будет возвращен достаточный объем памяти. (В случае если сборщик мусора не может возвратить достаточный объем памяти после полной сборки мусора, то он или расширит динамическую память, или выдаст OutOfMemoryError.)
Трассирующие сборщики мусора, например, копирующий, маркирующе-чистящий, и маркирующе-сжимающий, начинают сканирование с корневого набора, обходя по ссылкам между объектами до тех пор, пока все живые объекты не будут пройдены.
Трассирующий сборщик мусора, основанный на поколениях, начинает с корневого набора, но не переходит по ссылкам, ведущим к объектам в других, более старых поколениях, что уменьшает размер графа объектов, подлежащего трассировке. Основанные на поколениях сборщики мусора должны явно отслеживать ссылки более старших поколений на более молодые и добавлять эти ссылки в корневой набор вспомогательной сборки мусора. Есть два способа создать ссылку от старого объекта на молодой. Либо одна из ссылок, содержащихся в старом объекте, изменяется, чтобы ссылаться на молодой объект, или молодой объект, ссылающийся на другой молодой объект, перемещается в более старшее поколение.
Не важно, создается ли ссылка от старого объекта на молодой посредством перемещения или изменения указателя, в любом случае сборщику мусора необходим полный список ссылок старых объектов на молодые, если он хочет выполнить вспомогательную сборку мусора. Один из способов реализации - это трассировка старого поколения, но это явно очень затратно. В какой-то степени лучшим было бы линейное сканирование старого поколения в поисках ссылок на молодые объекты. Такой подход быстрее, чем трассировка, и обладает лучшей локальностью, но все же требует значительной работы.
Мутатор и сборщик мусора могут работать вместе, чтобы поддерживать полный список ссылок старых объектов на молодые по мере их создания. Если объекты перемещаются в более старое поколение, то сборщик мусора может отметить любые ссылки старых объектов на молодые, которые создаются в результате перемещения, что оставляет только трассировку ссылок между поколениями, созданных изменениями указателей.
В пакетах Sun JDK используется оптимизированный вариант алгоритма, называемый маркировкой карт, для определения изменения указателей, содержащихся в полях объектов старого поколения. В данном подходе динамическая память разделена на набор карт, каждая, из которых, обычно меньше, чем страница памяти. Виртуальная машина поддерживает схему карт, на которой один бит (или байт в некоторых версиях) соответствует одной карте в динамической памяти. При каждом изменении поля указателя объекта в динамической памяти, в схеме карт устанавливается соответствующий бит. Во время сборки мусора, маркирующие биты, связанные с картами в старом поколении проверяются, и грязные карты сканируются для нахождения объектов, содержащих ссылки на более молодое поколение. Затем эти биты стираются. Разметка на карты требует определенных затрат: дополнительного пространства для схемы карт, дополнительной работы, которая проделывается над каждым хранилищем указателя, и дополнительной работы во время сборки мусора. Алгоритмы маркировки карт могут добавить только три-четыре машинные команды на одно неинициализирующее хранилище указателя в динамической памяти. Это влечет за собой сканирование любых объектов в грязных картах во время вспомогательной сборки мусора.
По умолчанию пакет 1.4.1 JDK делит динамическую память на два сектора: молодое поколение и старое поколение. (На самом деле, есть еще третий сектор - постоянная область, которая используется для хранения загруженных объектов методов и классов). Молодое поколение делится на область порождения, часто называемую Эдемом, и два полупространства выживших объектов, в которых используется копирующий сборщик мусора.
В старом поколении используется маркирующе-сжимающий сборщик мусора. Объекты перемещаются из молодого поколения в старое после того, как они пережили копирование определенное число раз. Во время вспомогательной сборки мусора живые объекты из Эдема и одного из полупространств для выживших объектов копируются в другое полупространство, потенциально некоторые объекты перемещаются в более старое поколение. Основная сборка мусора затронет как молодое, так и старое поколение. Метод System.gc() всегда запускает основную сборку мусора.
Кроме копирующего и маркирующе-сжимающего сборщиков мусора, которые используются по умолчанию, в пакет 1.4.1 JDK также присутствуют четыре других алгоритма сборки мусора, каждый из которых используется для разных целей. JDK 1.4.1 содержит инкрементный сборщик и три новых сборщика для более эффективной работы на многопроцессорных системах: параллельный копирующий сборщик мусора, параллельный утилизирующий сборщик мусора и синхронизированный маркирующе-чистящий сборщик. Эти новые сборщики призваны решить проблему сборки мусора, которая является основным препятствием для решения проблемы масштабируемости на многопроцессорных системах.
Инкрементный сборщик мусора является частью пакета JDK, начиная с версии 1.2. Инкрементный сборщик мусора уменьшает паузы сборки мусора за счет производительности, и рекомендуется только в тех случаях, когда короткие паузы на сборку мусора очень важны, например, в системах с близким к реальному масштабом времени.
Алгоритм, используемый в JDK для инкрементной сборки мусора, так называемый алгоритм Train, создает в динамической памяти новую область между старым и новым поколениями. Эти области делятся на "составы", каждый из которых делится на последовательности "вагонов". Каждый вагон может обрабатываться сборщиком мусора отдельно. Фактически, каждый вагон представляет отдельное поколение. Это значит, что должны быть отслежены не только ссылки старых объектов на молодые, но и ссылки старых составов на молодые составы и старых вагонов на молодые вагоны. Это приводит к появлению достаточного количества дополнительной работы и для мутатора, и для сборщика мусора, но сокращает паузы на сборку мусора.
Новые сборщики в пакете JDK 1.4.1 разработаны для решения проблем со сборкой мусора на многопроцессорных системах. Так как большинство алгоритмов сборки мусора останавливают среду реализации на некоторый период времени, то однопотоковый сборщик мусора может быстро стать помехой для масштабируемости, так как все кроме одного процессора не работают, пока сборщик мусора приостановил потоки пользовательской программы. Два новых сборщика мусора созданы, чтобы уменьшить время, затрачиваемое на паузы: параллельный копирующий и синхронизированный маркирующе-чистящий сборщики. А параллельный утилизирующий сборщик мусора, создан для обеспечения большей производительности на больших объемах динамической памяти.
Параллельный копирующий сборщик мусора является копирующим сборщиком мусора молодого поколения, который разделяет сборку мусора между таким количеством потоков, какое имеется на процессоре. Синхронизированный маркирующе-чистящий сборщик является маркирующе-чистящим сборщиком старого поколения, который на краткий промежуток времени останавливает среду выполнения для начальной фазы маркировки (и еще раз позже для краткой повторной маркировки) и затем позволяет пользовательской программе возобновить работу, пока потоки сборщика мусора выполняются синхронно с пользовательской программой. Параллельный копирующий и синхронизированный маркирующе-чистящий сборщики по своей сути являются синхронизированными версиями используемых по умолчанию копирующего и маркирующе-сжимающего сборщиков мусора. Параллельный утилизирующий сборщик является сборщиком молодого поколения, оптимизированным для очень больших (гигабайт и более) объемов динамической памяти на многопроцессорных системах.