<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Александр Улизько &#187; Java</title>
	<atom:link href="http://ulizko.com/categories/development/java/feed" rel="self" type="application/rss+xml" />
	<link>http://ulizko.com</link>
	<description></description>
	<lastBuildDate>Wed, 24 Feb 2010 14:25:03 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Ваш JBoss AS еще не летает? Тогда мы идем к вам :)</title>
		<link>http://ulizko.com/posts/50</link>
		<comments>http://ulizko.com/posts/50#comments</comments>
		<pubDate>Thu, 11 Sep 2008 11:20:21 +0000</pubDate>
		<dc:creator>Александр Улизько</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[jboss]]></category>
		<category><![CDATA[tuning]]></category>

		<guid isPermaLink="false">http://ulizko.com/?p=50</guid>
		<description><![CDATA[Я забыл рассказать еще про одну фишку, которая ускорит работу вашего JBAS&#8217;a (JBAS == JBoss&#160;AS).
Большинство людей не знает, что такое RMI DGC. И большинству людей не нужно знать, что такое RMI DGC. Это я к тому, что мы с вами не входим в это большинство, так что по ссылке сходить стоит. Благо, текста там&#160;немного. 
Вне [...]]]></description>
			<content:encoded><![CDATA[<p>Я забыл рассказать еще про одну фишку, которая ускорит работу вашего JBAS&#8217;a (JBAS == JBoss&nbsp;AS).</p>
<p>Большинство людей не знает, что такое <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/rmi/dgc/package-summary.html">RMI DGC</a>. И большинству людей не нужно знать, что такое <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/rmi/dgc/package-summary.html">RMI DGC</a>. Это я к тому, что мы с вами не входим в это большинство, так что по ссылке сходить стоит. Благо, текста там&nbsp;немного. </p>
<p>Вне зависимости от того, используете ли вы в своем коде RMI или нет, JBAS подгружает подсистему RMI. По умолчанию, подсистема RMI запускает принудительную очистку мусора один раз в минуту. Это означает, что все потоки ставятся на паузу и проводится полное сканирование кучи. Это занимает довольно много времени, особенно, если сервер сильно&nbsp;нагружен. </p>
<p>Короче, чтобы JBOSS работал побыстрее, вставь эту строку в run.conf (который, напоминаю, расположен в $JBOSS_HOME/bin) куда-нибудь после того IF-a, что мы изменяли в <a href="http://ulizko.com/posts/45">предыдущей</a>&nbsp;статье:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #007800;">JAVA_OPTS</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$JAVA_OPTS</span> -Dsun.rmi.dgc.client.gcInterval=3600000 
-Dsun.rmi.dgc.server.gcInterval=3600000&quot;</span></pre></div></div>

<p>(Обратный слеш  в данном случае не имеет никакого значения, он просто экранирует перевод каретки, чтобы строка кода влезла в формат поста. Когда будешь вставлять эту строку, можешь просто срастить эти две строки в одну, а слеш&nbsp;удалить.)</p>
<p>Есть еще один вариант. Можно запретить любому коду (в том числе и RMI подсистеме) запускать принудительную очистку мусора ,так что вместо вышеуказанных опций можно указать <code>XX:+DisableExplicitGC</code>. В этом случае сборка мусора будет запускаться если куча будет заполнена примерно на 70% (это дефолтное значение и оно тоже&nbsp;настраивается).</p>
<p>Какой из двух вариантов использовать? Не знаю, пока тестирую оба, посмотрим, что&nbsp;получится. </p>
<p>Возникает вопрос, а когда нужно это поведение-по-умолчанию RMI DGC? Никогда. Конечно, если твой код выполняет кучу вызовов удаленных объектов (remote object calls) (EJB, привет! :) и при этом не кэширует ваши LOCAL или REMOTE объекты, то тогда, _возможно_, очистки мусора раз в час будет&nbsp;недостаточно. </p>
<p>Те, кто хотят узнать побольше про управлению памятью, могут почитать вот <a href="http://ulizko.com/posts/44">эти</a> <a href="http://ulizko.com/posts/45">мои</a>&nbsp;статьи.</p>
]]></content:encoded>
			<wfw:commentRss>http://ulizko.com/posts/50/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Java. Сборщики мусора. Часть вторая.</title>
		<link>http://ulizko.com/posts/45</link>
		<comments>http://ulizko.com/posts/45#comments</comments>
		<pubDate>Wed, 09 Jul 2008 12:25:33 +0000</pubDate>
		<dc:creator>Александр Улизько</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[garbage collector]]></category>
		<category><![CDATA[permGen]]></category>
		<category><![CDATA[theory]]></category>

		<guid isPermaLink="false">http://ulizko.com/posts/45</guid>
		<description><![CDATA[Это продолжение вчерашнего поста про сборщики мусора в JavaTM. Напоминаю, что все эту бодягу я начал с целью разобраться, что такое ошибка PermGenSpace: OutOfMemory&#160;exception.

Прежде чем рассказать о том, как работает сборка мусора в современной JVM (1.4, 1.5), давайте поговорим о поколениях объектов.  В динамической памяти приложения некоторые объекты становятся мусором вскоре после создания, некоторые [...]]]></description>
			<content:encoded><![CDATA[<p>Это продолжение <a href="http://ulizko.com/posts/44">вчерашнего поста</a> про сборщики мусора в Java<sup>TM</sup>. Напоминаю, что все эту бодягу я начал с целью разобраться, что такое ошибка PermGenSpace: OutOfMemory&nbsp;exception.</p>
<p><span id="more-45"></span></p>
<p>Прежде чем рассказать о том, как работает сборка мусора в современной JVM (1.4, 1.5), давайте поговорим о поколениях объектов.  В динамической памяти приложения некоторые объекты становятся мусором вскоре после создания, некоторые живут в течение долгого времени и только затем становятся мусором, другие могут остаться в живых в течение всего времени работы программы. Как показывает практика, в большинстве объектно-ориентированных языков, включая Java, огромное количество объектов, приблизительно 98 % , умирают молодыми. Возраст объектов можно измерять в секундах настенных часов, в общем количестве байтов, выделенных подсистемой управления памятью, с тех пор, как объект был размещен, или в числе сборок мусора с момента размещения объекта. Но как бы Вы не измеряли, большинство исследований показывает, что объекты умирают молодыми.  Тут я даже постарался и с помощью  <a href="http://www.clabberhead.com/googlechartgenerator.html">Google Chart Creator</a> нарисовал график:  <a href="http://ulizko.com/wp-content/uploads/2008/09/chart.png"><img class="alignnone size-full wp-image-64" title="Распределение объектов по поколениям" src="http://ulizko.com/wp-content/uploads/2008/09/chart.png" alt="" width="500" height="250" /></a> Так как мы живем в неидеальном мире, у каждого из этих алгоритмов есть как преимущества, так и недостатки. Например, копирование хорошо работает, когда большой процент объектов является мусором (потому что этот вид сборщиков мусора не посещает мертвые объкты&thinsp;&#8211;&thinsp;он просто копирует живые объекты), но плохо работает с большим количеством долгоживущих объектов (периодически выполняя их копирование). Наоборот, маркировка-сжатие вполне хорошо работает с долгоживущими объектами (копируя их только один раз), но не так хорошо с большим количеством объектов, живущих недолго.  Теперь, зная это, можно сделать вывод, что лучшим вариантом сборки мусора было бы использование копирующего сборщика мусора, а для долгоживущих&thinsp;&#8211;&thinsp;маркирующе-сжимающего.  На основе подобных рассуждений, в Java был введен метод сборки мусора, берущий лучшее от обоих алгоритмов и нивелирующих их недостатки: так называемая &laquo;основанная на поколениях сборка мусора&raquo;. Дополнительно он обеспечивает очень низкие затраты на размещение&nbsp;объектов.</p>
<h2>Сборка мусора на основе&nbsp;поколений</h2>
<p><img title="Распределение виртуальной памяти по поколениям" src="http://ulizko.com/wp-content/uploads/2008/07/generations.png" border="0" alt="" /> Сборщик мусора, основанный на поколениях, делит динамическую память на несколько поколений&thinsp;&#8211;&thinsp;youth (молодые), tenured (Дословно&thinsp;&#8211;&thinsp;выжившие. На мой взгляд, очень поэтично :), perm&thinsp;&#8211;&thinsp;вечные. Youth дополнително делится на область генерации объектов Eden (совсем поэтично) и две полузоны для работы копирующего сборщика. Я еще не говорил. Объекты, отвечающие некоторым критериям продвижения, например, они пережили определенное число сборок мусора, затем переводятся в более старшее поколение&thinsp;&#8211;&thinsp;сначала Tenured (убирается маркирующе-сжимающим сборщиком мусора), затем и Perm (вообще не убирается).  Одно из преимуществ сборки мусора на основе поколений заключается в том, что она может сократить паузы, не обрабатывая все поколения сразу. Если распределитель ресурсов не способен выполнить запросы на размещение, то он сначала запускает вспомогательные сборки мусора, которые обрабатывают только самое младшее поколение. Так как многие объекты в молодом поколении будут уже мертвы, а копирующему сборщику мусора совсем не надо проверять мертвые объекты, то паузы на вспомогательные сборки мусора могут быть достаточно малыми, и зачастую могут возвращать значительный объем динамической памяти. Если вспомогательная сборка мусора освобождает достаточно места в динамической памяти, то мутатор может немедленно возобновить работу. Если же она освобождает недостаточно места в динамической памяти, то сборка продолжится в более старших поколениях до тех пор, пока не будет возвращен достаточный объем памяти. (В случае если сборщик мусора не может возвратить достаточный объем памяти после полной сборки мусора, то он или расширит динамическую память, или выдаст OutOfMemoryError.)  В принципе, уже из этого понятно, что такое PermGen, и почему у него заканчивается место при redeploy&#8217;е. Желающие узнать больше о принципах работы поколенного сборщика мусора могут обратиться к еще одной статье <a href="http://www.briangoetz.com/">Брайна Гетца</a> &laquo;<a href="http://www.ibm.com/developerworks/ru/library/j-jtp11253/index.html">Сборка мусора в HotSpot JVM</a>&laquo;.  Отдельно стоит упомянуть про многопроцессорные системы. В ранних версиях JDK сборка мусора в параллельных потоках сильно замедляла работу систему. Я даже спиздел из статьи <a href="http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html">Tuning Collection with the 5.0 Java[tm] Virtual Machine</a> классную картинку, которая визуализирует зависимость между временем сборки мусора и количеством процессоров:  <a href="http://ulizko.com/wp-content/uploads/2008/09/proc_throughput_chart.png"><img class="alignnone size-full wp-image-65" title="Падение производительности сборщика мусора при увеличении количества процессоров" src="http://ulizko.com/wp-content/uploads/2008/09/proc_throughput_chart.png" alt="" width="500" height="377" /></a>    К счастью, в JDK 1.4 добавили специально для таких систем еще три сборщика мусора: параллельный копирующий сборщик мусора, параллельный утилизирующий сборщик мусора и синхронизированный маркирующе-чистящий сборщик. Эти новые сборщики призваны решить проблему сборки мусора, которая является основным припятствием для решения проблемы масштабируемости на многопроцессорных системах.  Ну и напоследок еще одна пизженная у Брайна Гетца картинка, на которой проиллюстрированы рекомендации для выбора сборщика мусора:  <a href="http://ulizko.com/wp-content/uploads/2008/09/gc-options.png"><img class="alignnone size-full wp-image-66" title="Рекомендации выбора сборщика мусора" src="http://ulizko.com/wp-content/uploads/2008/09/gc-options.png" alt="" width="500" height="213" /></a>&nbsp; </p>
<h2>Настройка JBOSS&nbsp;AS</h2>
<p>PermGen Space : OutOfMemory exception вылетает от того, что оставшиеся от предыдущего deploy&#8217;я вечные объекты так и остаются в PermGen (это я не знаю, а предполагаю&thinsp;&#8211;&thinsp;и могу ошибаться) и PermGen Space рано или поздно переполняется. Соответственно, для решения этой проблемы нам надо как-то заставить сборщик мусора убирать более не нужные объекты в PermGen.  На практике это выглядит так:  1. открываем файл run.conf в папке bin jboss&#8217;a, находим строку, начинающуюся с JAVA_OPTS и добавляем в нее следующие параметры: 2. Разрешаем сборщику мусора убирать PermGen: <code>-XX:+CMSPermGenSweepingEnabled</code> 3. Так как JVM так просто не отдаст на растерзание Perm объекты, надо умилостивить ее: <code>-XX:+CMSClassUnloadingEnabled</code> 4. Для того, чтобы сборщик мусора не прибил нужные нам объекты, нам нужно увеличить размер PermGen: <code>-XX:MaxPermSize=128m</code> 5. (Опционально) Если jboss вертится на многопроцессорной системе, то не забудьте включить синхронизированный сборщик мусора: <code>-XX:+UseConcMarkSweepGC</code> Для удобства использования выложу мою строку&nbsp;JAVA_OPTS:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #007800;">JAVA_OPTS</span>=<span style="color: #ff0000;">&quot;-Xms256m -Xmx1024m -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -XX:+UseConcMarkSweepGC -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=128m&quot;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://ulizko.com/posts/45/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Java. Сборщики мусора. Часть первая.</title>
		<link>http://ulizko.com/posts/44</link>
		<comments>http://ulizko.com/posts/44#comments</comments>
		<pubDate>Tue, 08 Jul 2008 05:20:36 +0000</pubDate>
		<dc:creator>Александр Улизько</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[garbage collector]]></category>
		<category><![CDATA[theory]]></category>

		<guid isPermaLink="false">http://ulizko.com/posts/44</guid>
		<description><![CDATA[Честно признаюсь&#8201;&#8211;&#8201;я жутко ленив. Я не люблю копаться в чем-то, добиваясь наилучшего быстродействия. Я могу, к примеру, полгода перешагивать через провод удлинителя, протянутый через всю комнату, пока однажды, споткнувшись, не оторву его нахуй. Вот после этого я наконец-то озадачусь протягиванием нормальной проводки до нужного угла комнаты или сделаю перестановку. Но не&#160;раньше. 
Примерно так же я [...]]]></description>
			<content:encoded><![CDATA[<p>Честно признаюсь&thinsp;&#8211;&thinsp;я жутко ленив. Я не люблю копаться в чем-то, добиваясь наилучшего быстродействия. Я могу, к примеру, полгода перешагивать через провод удлинителя, протянутый через всю комнату, пока однажды, споткнувшись, не оторву его нахуй. Вот после этого я наконец-то озадачусь протягиванием нормальной проводки до нужного угла комнаты или сделаю перестановку. Но не&nbsp;раньше. </p>
<p>Примерно так же я относился до недавнего времени к регулярно вылетающим PermGen: OutOfMemory exception от <a href="http://www.jboss.org/jbossas/">JBOSS Application Server</a> на моем ноуте. Ну, бывает иногда, и хуй с&nbsp;ним.</p>
<p>Пока однажды я не заметил, что перезапускаю сервер по три-четыре раза в час, теряя на этом минут пять. Пять минут в час, если кто не понял&thinsp;&#8211;&thinsp;это 730 часов в год или 30 дней, или месяц. Месяц тупого пяленья в мелькающие в консоли строки загрузки сервера и initial deploy&#8217;я проекта!&nbsp;Блядь!</p>
<p>И я решил раскопать, что именно вызывает этот самый PermGen: OutOfMemory exception. Чтобы, разумеется, &laquo;протянуть нормальную&nbsp;проводку&raquo;.</p>
<p>Прежде чем начинать разговор о том, что такое PermGen, и почему в нем заканчивается место, а также как это поправить, я расскажу на пальцах, как Java<sup>TM</sup> работает с памятью, что такое сборщики мусора, какие виды сборщиков мусора бывают и как они работают в современных&nbsp;JVM.</p>
<h2>I. Общие&nbsp;слова</h2>
<p>Так уж исторически сложилось, что в отношении работы с памятью Java сравнивают с c++. Корни такого подхода лежат еще в тех временах, когда Java нигде толком не использовалась, но уже активно рекламировалась и им нужно было как-то перетягивать разработчиков с&nbsp;c++.</p>
<p>В c++ в общем случае выделение памяти происходит явно с помощью явно написанного конструктора, в котором разработчик часто вручную управляет выделением памяти с помощью операторов malloc/calloc, причем разработчику надо явно проинициализировать переменные, с которыми он работает. Удаление объекта производится вызовом деструктора, который также пишется вручную, и лучше бы ему не забыть очистить всю память, которую он выделил под объект, иначе он замудохается искать, куда утекает память&nbsp;приложения.</p>
<p>В Java<sup>TM</sup> возлагает на виртуальную машину управление памятью&thinsp;&#8211;&thinsp;выделение памяти под объекты, удаление объектов, освобождение памяти. В том же самом общем случае объекты хранятся в куче, а не в стеке (за исключением примитивных типов), что увеличивает время выделение памяти и доступа к объекту. Зато JVM их 100% проинициализирует, так что вы не получите -44441222, обратившись к непроинициалированному явно&nbsp;int&#8217;у. </p>
<p>Во-вторых, удалением объекта и освобождением памяти занимается не вручную написанный деструктор, а сборщик мусора (garbage collector), работающий в параллельном потоке. Что, с одной стороны, очень хорошо&thinsp;&#8211;&thinsp;теперь программисту не нужно думать о том, прибрался ли он за собой, а также о том, где взять память, но, с другой стороны, неизвестно, когда именно сборщик мусора утилизует объект и отдаст свободную память. Не говоря уж о том, что сборщик мусора тоже требует для своей работы системных&nbsp;ресурсов.</p>
<h2>II. Выделение&nbsp;памяти</h2>
<p>Прежде чем переходить к сборщикам мусора, не лишним будет напомнить, как происходит выделение памяти под&nbsp;объекты:</p>
<p>Рассмотрим простейший&nbsp;пример:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> FuckingExample <span style="color: #009900;">&#123;</span>
    <span style="color: #000066; font-weight: bold;">int</span> x<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
FuckingExample boolShit <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> FuckingExample<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>С помощью оператора new мы можем создать новый объект. При этом JVM самостоятельно выделит память под объект и проинициализирует его поля (в данном примере&thinsp;&#8211;&thinsp;x). В отличии от C++ в Java не нужно писать конструктор по умолчанию&thinsp;&#8211;&thinsp;JVM в случае его отсутствия самостоятельно справится с инициализацией&nbsp;объекта.</p>
<p>В отличии от все того же многострадального C++ не нужно явно инициализировать поля с примитивными типами&thinsp;&#8211;&thinsp;JVM дает гарантию, что присвоит переменной примитивного типа значение этого типа по умолчанию. Другими словами, вы можете быть уверенными, что в случае, если вы явно не проинициалируете переменную, как в примере, то значение x будет равно 0, а не мусору, как было бы в&nbsp;C++.</p>
<p>Впрочем, <em>не все</em> объекты располагаются в куче. Для примитивных типов сделано исключение, они располагаются в стеке. Если же нужен не примитивный тип int, а объект типа Integer (ну, к примеру, тебе понадобились специфические метода этого объекта), то надо объявить его&nbsp;так:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #003399;">Integer</span> x <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Integer</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>В этом случае x является экземляром класса Integer и располагаться в&nbsp;куче.</p>
<p>На этом месте я закончу с выделением памяти, интересующиеся могут обратиться к книге <a href="http://www.mindviewinc.com/Index.php">Брюса Экеля</a> &laquo;<a href="http://www.ozon.ru/context/detail/id/1498360/">Философия JAVA</a>&raquo; или к <a href="http://java.sun.com/docs/books/jls/third_edition/html/j3TOC.html">спецификации&nbsp;языка</a></p>
<h2>III. Освобождение памяти. Алгоритмы сборщиков&nbsp;мусора</h2>
<p>Надеюсь, все заметили, что в примере, приведенном выше, у класса FuckingExample нет деструктора. Это потому, что он не нужен. После того, как объект станет (на него не будет ссылки из статической переменной или активного фрейма стека), он будет передан сборщику мусора, который очистит от него память и вернет эту свободную память&nbsp;приложению. </p>
<p>Как же именно работают эти самые сборщики мусора? Ответ на это дает нам статья <a href="http://www.briangoetz.com/">Брайана Гетца</a> &laquo;<a href="http://www.ibm.com/developerworks/ru/library/j-jtp10283/index.html">Краткая история развития технологии утилизации памяти</a>&laquo;, которую я бессовестно спиздел, слегка&nbsp;переработав.</p>
<p>Выделяют два типа алгоритмов сборщика мусора: подсчет ссылок и трассирующие сборщики&nbsp;мусора.</p>
<h4>Подсчет&nbsp;ссылок</h4>
<p>Идея очень простая: Каждый объект имеет ассоциированное с ним количество ссылок&thinsp;&#8211;&thinsp;число активных ссылок на данный объект. Если количество ссылок равно нулю&thinsp;&#8211;&thinsp;это мусор (недоступный для пользовательской программы), и он может быть переработан.<br />
Но эта простая идея требует значительной поддержки от компилятора и даёт дополнительную избыточность для мутатора (термин для пользовательской программы с точки зрения сборщика мусора). Каждый раз, когда модифицируется ссылка на указатель, например, с помощью оператора присваивания, или когда ссылка выходит за границу, компилятор должен генерировать код для того, чтобы обновить количество ссылок на указываемый объект. Если количество ссылок на объект доходит до нуля, среда выполнения может вернуть блок информации немедленно (и уменьшить количество ссылок для всех блоков, на которые ссылается возвращаемый блок) или поместить его в очередь для отсроченной&nbsp;утилизации.</p>
<p>Собственно, это все, что нужно знать про этот алгоритм сборки мусора. Все равно он на практике сейчас не&nbsp;используется.</p>
<h4>Трассирующие сборщики&nbsp;мусора</h4>
<p>Трассирующий сборщик останавливает приложение (хоть это и не нужно на весь период сборки мусора) и начинают трассировать объекты, начиная с корневого набора, и проходят по всем ссылкам, пока все доступные объекты не будут проверены. Корни могут быть найдены в регистрах программ, в локальных (стековых) переменных, в стеке каждого из потоков и в статических&nbsp;переменных.</p>
<h4>Маркирующе-зачищающие сборщики&nbsp;мусора</h4>
<p>Наиболее простая форма трассирующего сборщика мусора, впервые предложенная создателем языка Lisp Джоном Маккарти в 1960г.,&thinsp;&#8211;&thinsp;это маркирующе-зачищающий сборщик, в котором среда выполнения останавливается, и сборщик посещает каждый живой узел, начиная с корней, и маркирует каждый посещённый узел. Когда не существует больше не отслеженных ссылок, сборка мусора завершена, и затем динамическая память зачищается (то есть каждый объект динамической памяти проверяется), а любой непомеченный объект регенерируется как мусор и возвращается в список свободной&nbsp;памяти. </p>
<p>Маркировка-зачистка проста для реализации, может легко восстанавливать циклические структуры и не даёт дополнительной нагрузки на компилятор или мутатор как подсчёт ссылок. Но у неё есть недостатки&thinsp;&#8211;&thinsp;паузы на сбор мусора могут быть долгими, и вся динамическая память посещается в фазе зачистки, что может иметь весьма негативные последствия на работу систем с виртуальной памятью, где динамическая память может быть разбита на&nbsp;страницы.</p>
<p>Большая проблема с маркировкой-зачисткой состоит в том, что каждый активный (то есть, распределённый) объект, доступен он или нет, посещается в фазе зачистки. Потому что значительный процент объектов, вероятно, окажется мусором, что означает, что сборщик тратит значительные усилия на проверку и обработку мусора. Маркирующе-зачищающие сборщики мусора также имеют тенденцию фрагментировать динамическую память, что может вызвать проблемы с локализацией и может также стать причиной ошибок выделения памяти, даже когда доступно достаточное количество свободной&nbsp;памяти.</p>
<h4>Копирующие сборщики&nbsp;мусора</h4>
<p>В копирующем сборщике, другом виде маркирующего сборщика, динамическая память делится на две равные по размеру части, одна из которых содержит активные данные, а другая не используется. Когда активная часть заполнена, среда выполнения останавливается, и действующие объекты копируются из активной части в неактивную. При этом части меняются своими ролями: старая неактивная часть становится активной и&nbsp;наоборот.</p>
<p>Преимущество копирующих сборщиков мусора состоит в том, что они посещают только живые объекты, что означает, что объекты мусора не будут исследоваться, им не потребуется подкачка в память и помещение в кэш. Продолжительность циклов сборки мусора копирующего сборщика зависит от количества живых объектов. Однако, копирующие сборщики создают дополнительные затраты на копирование данных из одной части в другую с исправлением всех ссылок на местонахождение новой копии. В частности, долгоживущие объекты будут копироваться туда-сюда при каждой сборке&nbsp;мусора.</p>
<p>Копирующие сборщики приносят пользу ещё и тем, что живые объекты уплотняются в нижнюю часть динамической памяти. Это не только улучшает локальность ссылок пользовательской программы и позволяет избежать фрагментации динамической памяти, но и значительно уменьшает затраты на размещение объекта. Эта процедура становится просто добавлением ссылки к указателю вершины динамической памяти. Нет необходимости поддерживать списки свободной памяти или сохраняющиеся списки или выполнять алгоритмы наилучшей подгонки или первого подходящего&thinsp;&#8211;&thinsp;выделение места для N байт сводится к добавлению N к указателю вершины динамической памяти и возвращению его предыдущего&nbsp;значения.</p>
<p>Разработчики, которые использовали сложные схемы управления памятью для языков, не использующих сборщики мусора, могли бы сильно удивиться тому, насколько незатратным может быть распределение памяти&thinsp;&#8211;&thinsp;простое добавление ссылки&thinsp;&#8211;&thinsp;в копирующем сборщике мусора. Это может быть одной из причин распространённого мнения, что распределение объектов связанно с затратами, в более ранних версиях виртуальной машины Java не использовались копирующие сборщики мусора, и разработчики все еще подспудно считают, что затраты на распределение такие же, как в других языках, типа C, тогда как на самом деле они могут быть значительно меньше в исполняемой среде Java. Но не только издержки на распределение памяти меньше, но также для объектов, которые превратились в мусор до начала следующего цикла сборки, затраты на освобождение памяти равны нулю, так как утилизируемый объект не будет ни проверяться, ни&nbsp;копироваться.</p>
<h4>Маркирующе-сжимающие сборщики&nbsp;мусора</h4>
<p>Копирующий алгоритм имеет прекрасные рабочие характеристики, но его основным недостатком является потребность в объёме памяти большем в два раза, чем объём, необходимый для маркирующе-зачищающего сборщика мусора. Алгоритм маркировки-сжатия сочетает маркировку-зачистку и копирование таким образом, что эта проблема исчезает за счет того, что процесс сборки мусора усложняется. Как и маркировка-зачистка, маркировка-сжатие состоит из двух фаз. В фазе маркировки каждый действующий объект рассматривается и маркируется. Затем маркированные объекты копируются таким образом, что все действующие объекты уплотняются в самом низу динамической памяти. Если полное сжатие совершается при каждой сборке мусора, полученная в результате динамическая память такая же как и результат работы копирующего сборщика&thinsp;&#8211;&thinsp;между активной частью динамической памяти и свободной существует чёткая граница, так что затраты на размещение сравнимы с затратами при использовании копирующего сборщика мусора. Долгоживущие объекты имеют тенденцию накапливаться в самом низу динамической памяти, поэтому они не копируются циклически, как при использовании копирующего сборщика&nbsp;мусора.</p>
]]></content:encoded>
			<wfw:commentRss>http://ulizko.com/posts/44/feed</wfw:commentRss>
		<slash:comments>347</slash:comments>
		</item>
	</channel>
</rss>
