Честно признаюсь – я жутко ленив. Я не люблю копаться в чем-то, добиваясь наилучшего быстродействия. Я могу, к примеру, полгода перешагивать через провод удлинителя, протянутый через всю комнату, пока однажды, споткнувшись, не оторву его нахуй. Вот после этого я наконец-то озадачусь протягиванием нормальной проводки до нужного угла комнаты или сделаю перестановку. Но не раньше.
Примерно так же я относился до недавнего времени к регулярно вылетающим PermGen: OutOfMemory exception от JBOSS Application Server на моем ноуте. Ну, бывает иногда, и хуй с ним.
Пока однажды я не заметил, что перезапускаю сервер по три-четыре раза в час, теряя на этом минут пять. Пять минут в час, если кто не понял – это 730 часов в год или 30 дней, или месяц. Месяц тупого пяленья в мелькающие в консоли строки загрузки сервера и initial deploy’я проекта! Блядь!
И я решил раскопать, что именно вызывает этот самый PermGen: OutOfMemory exception. Чтобы, разумеется, «протянуть нормальную проводку».
Прежде чем начинать разговор о том, что такое PermGen, и почему в нем заканчивается место, а также как это поправить, я расскажу на пальцах, как JavaTM работает с памятью, что такое сборщики мусора, какие виды сборщиков мусора бывают и как они работают в современных JVM.
I. Общие слова
Так уж исторически сложилось, что в отношении работы с памятью Java сравнивают с c++. Корни такого подхода лежат еще в тех временах, когда Java нигде толком не использовалась, но уже активно рекламировалась и им нужно было как-то перетягивать разработчиков с c++.
В c++ в общем случае выделение памяти происходит явно с помощью явно написанного конструктора, в котором разработчик часто вручную управляет выделением памяти с помощью операторов malloc/calloc, причем разработчику надо явно проинициализировать переменные, с которыми он работает. Удаление объекта производится вызовом деструктора, который также пишется вручную, и лучше бы ему не забыть очистить всю память, которую он выделил под объект, иначе он замудохается искать, куда утекает память приложения.
В JavaTM возлагает на виртуальную машину управление памятью – выделение памяти под объекты, удаление объектов, освобождение памяти. В том же самом общем случае объекты хранятся в куче, а не в стеке (за исключением примитивных типов), что увеличивает время выделение памяти и доступа к объекту. Зато JVM их 100% проинициализирует, так что вы не получите -44441222, обратившись к непроинициалированному явно int’у.
Во-вторых, удалением объекта и освобождением памяти занимается не вручную написанный деструктор, а сборщик мусора (garbage collector), работающий в параллельном потоке. Что, с одной стороны, очень хорошо – теперь программисту не нужно думать о том, прибрался ли он за собой, а также о том, где взять память, но, с другой стороны, неизвестно, когда именно сборщик мусора утилизует объект и отдаст свободную память. Не говоря уж о том, что сборщик мусора тоже требует для своей работы системных ресурсов.
II. Выделение памяти
Прежде чем переходить к сборщикам мусора, не лишним будет напомнить, как происходит выделение памяти под объекты:
Рассмотрим простейший пример:
public class FuckingExample { int x; } FuckingExample boolShit = new FuckingExample();
С помощью оператора new мы можем создать новый объект. При этом JVM самостоятельно выделит память под объект и проинициализирует его поля (в данном примере – x). В отличии от C++ в Java не нужно писать конструктор по умолчанию – JVM в случае его отсутствия самостоятельно справится с инициализацией объекта.
В отличии от все того же многострадального C++ не нужно явно инициализировать поля с примитивными типами – JVM дает гарантию, что присвоит переменной примитивного типа значение этого типа по умолчанию. Другими словами, вы можете быть уверенными, что в случае, если вы явно не проинициалируете переменную, как в примере, то значение x будет равно 0, а не мусору, как было бы в C++.
Впрочем, не все объекты располагаются в куче. Для примитивных типов сделано исключение, они располагаются в стеке. Если же нужен не примитивный тип int, а объект типа Integer (ну, к примеру, тебе понадобились специфические метода этого объекта), то надо объявить его так:
Integer x = new Integer(2);
В этом случае x является экземляром класса Integer и располагаться в куче.
На этом месте я закончу с выделением памяти, интересующиеся могут обратиться к книге Брюса Экеля «Философия JAVA» или к спецификации языка
III. Освобождение памяти. Алгоритмы сборщиков мусора
Надеюсь, все заметили, что в примере, приведенном выше, у класса FuckingExample нет деструктора. Это потому, что он не нужен. После того, как объект станет (на него не будет ссылки из статической переменной или активного фрейма стека), он будет передан сборщику мусора, который очистит от него память и вернет эту свободную память приложению.
Как же именно работают эти самые сборщики мусора? Ответ на это дает нам статья Брайана Гетца «Краткая история развития технологии утилизации памяти«, которую я бессовестно спиздел, слегка переработав.
Выделяют два типа алгоритмов сборщика мусора: подсчет ссылок и трассирующие сборщики мусора.
Подсчет ссылок
Идея очень простая: Каждый объект имеет ассоциированное с ним количество ссылок – число активных ссылок на данный объект. Если количество ссылок равно нулю – это мусор (недоступный для пользовательской программы), и он может быть переработан.
Но эта простая идея требует значительной поддержки от компилятора и даёт дополнительную избыточность для мутатора (термин для пользовательской программы с точки зрения сборщика мусора). Каждый раз, когда модифицируется ссылка на указатель, например, с помощью оператора присваивания, или когда ссылка выходит за границу, компилятор должен генерировать код для того, чтобы обновить количество ссылок на указываемый объект. Если количество ссылок на объект доходит до нуля, среда выполнения может вернуть блок информации немедленно (и уменьшить количество ссылок для всех блоков, на которые ссылается возвращаемый блок) или поместить его в очередь для отсроченной утилизации.
Собственно, это все, что нужно знать про этот алгоритм сборки мусора. Все равно он на практике сейчас не используется.
Трассирующие сборщики мусора
Трассирующий сборщик останавливает приложение (хоть это и не нужно на весь период сборки мусора) и начинают трассировать объекты, начиная с корневого набора, и проходят по всем ссылкам, пока все доступные объекты не будут проверены. Корни могут быть найдены в регистрах программ, в локальных (стековых) переменных, в стеке каждого из потоков и в статических переменных.
Маркирующе-зачищающие сборщики мусора
Наиболее простая форма трассирующего сборщика мусора, впервые предложенная создателем языка Lisp Джоном Маккарти в 1960г., – это маркирующе-зачищающий сборщик, в котором среда выполнения останавливается, и сборщик посещает каждый живой узел, начиная с корней, и маркирует каждый посещённый узел. Когда не существует больше не отслеженных ссылок, сборка мусора завершена, и затем динамическая память зачищается (то есть каждый объект динамической памяти проверяется), а любой непомеченный объект регенерируется как мусор и возвращается в список свободной памяти.
Маркировка-зачистка проста для реализации, может легко восстанавливать циклические структуры и не даёт дополнительной нагрузки на компилятор или мутатор как подсчёт ссылок. Но у неё есть недостатки – паузы на сбор мусора могут быть долгими, и вся динамическая память посещается в фазе зачистки, что может иметь весьма негативные последствия на работу систем с виртуальной памятью, где динамическая память может быть разбита на страницы.
Большая проблема с маркировкой-зачисткой состоит в том, что каждый активный (то есть, распределённый) объект, доступен он или нет, посещается в фазе зачистки. Потому что значительный процент объектов, вероятно, окажется мусором, что означает, что сборщик тратит значительные усилия на проверку и обработку мусора. Маркирующе-зачищающие сборщики мусора также имеют тенденцию фрагментировать динамическую память, что может вызвать проблемы с локализацией и может также стать причиной ошибок выделения памяти, даже когда доступно достаточное количество свободной памяти.
Копирующие сборщики мусора
В копирующем сборщике, другом виде маркирующего сборщика, динамическая память делится на две равные по размеру части, одна из которых содержит активные данные, а другая не используется. Когда активная часть заполнена, среда выполнения останавливается, и действующие объекты копируются из активной части в неактивную. При этом части меняются своими ролями: старая неактивная часть становится активной и наоборот.
Преимущество копирующих сборщиков мусора состоит в том, что они посещают только живые объекты, что означает, что объекты мусора не будут исследоваться, им не потребуется подкачка в память и помещение в кэш. Продолжительность циклов сборки мусора копирующего сборщика зависит от количества живых объектов. Однако, копирующие сборщики создают дополнительные затраты на копирование данных из одной части в другую с исправлением всех ссылок на местонахождение новой копии. В частности, долгоживущие объекты будут копироваться туда-сюда при каждой сборке мусора.
Копирующие сборщики приносят пользу ещё и тем, что живые объекты уплотняются в нижнюю часть динамической памяти. Это не только улучшает локальность ссылок пользовательской программы и позволяет избежать фрагментации динамической памяти, но и значительно уменьшает затраты на размещение объекта. Эта процедура становится просто добавлением ссылки к указателю вершины динамической памяти. Нет необходимости поддерживать списки свободной памяти или сохраняющиеся списки или выполнять алгоритмы наилучшей подгонки или первого подходящего – выделение места для N байт сводится к добавлению N к указателю вершины динамической памяти и возвращению его предыдущего значения.
Разработчики, которые использовали сложные схемы управления памятью для языков, не использующих сборщики мусора, могли бы сильно удивиться тому, насколько незатратным может быть распределение памяти – простое добавление ссылки – в копирующем сборщике мусора. Это может быть одной из причин распространённого мнения, что распределение объектов связанно с затратами, в более ранних версиях виртуальной машины Java не использовались копирующие сборщики мусора, и разработчики все еще подспудно считают, что затраты на распределение такие же, как в других языках, типа C, тогда как на самом деле они могут быть значительно меньше в исполняемой среде Java. Но не только издержки на распределение памяти меньше, но также для объектов, которые превратились в мусор до начала следующего цикла сборки, затраты на освобождение памяти равны нулю, так как утилизируемый объект не будет ни проверяться, ни копироваться.
Маркирующе-сжимающие сборщики мусора
Копирующий алгоритм имеет прекрасные рабочие характеристики, но его основным недостатком является потребность в объёме памяти большем в два раза, чем объём, необходимый для маркирующе-зачищающего сборщика мусора. Алгоритм маркировки-сжатия сочетает маркировку-зачистку и копирование таким образом, что эта проблема исчезает за счет того, что процесс сборки мусора усложняется. Как и маркировка-зачистка, маркировка-сжатие состоит из двух фаз. В фазе маркировки каждый действующий объект рассматривается и маркируется. Затем маркированные объекты копируются таким образом, что все действующие объекты уплотняются в самом низу динамической памяти. Если полное сжатие совершается при каждой сборке мусора, полученная в результате динамическая память такая же как и результат работы копирующего сборщика – между активной частью динамической памяти и свободной существует чёткая граница, так что затраты на размещение сравнимы с затратами при использовании копирующего сборщика мусора. Долгоживущие объекты имеют тенденцию накапливаться в самом низу динамической памяти, поэтому они не копируются циклически, как при использовании копирующего сборщика мусора.
New flash casino no money deposit…
New flash casino no money deposit…
Rtg chip codes…
Rtg chip codes…
Free no deposit bonus royal card room…
Free no deposit bonus royal card room…
Microgaming bonus liste…
Microgaming bonus liste…
Casino no deposite new…
Casino no deposite new…
Downloadable games no money…
Downloadable games no money…
2009 rtg no deposit bonus coupon codes…
2009 rtg no deposit bonus coupon codes…
Newest no deposit rtg codes in march 2009…
Newest no deposit rtg codes in march 2009…
No deposit casinos with free money…
No deposit casinos with free money…
Casino-free chip…
Casino-free chip…
Slot no deposit…
Slot no deposit…
No download slots bouns cash…
No download slots bouns cash…
Free no deposit bonus bonus code…
Free no deposit bonus bonus code…
Free play casinos…
Free play casinos…
Online casino coupon codes…
Online casino coupon codes…
Vip lounge casino bonus…
Vip lounge casino bonus…
Bingo free code…
Bingo free code…
Online casinos with nodeposit signup bonus…
Online casinos with nodeposit signup bonus…
New 2009 rtg bonus codes…
New 2009 rtg bonus codes…
Newest rtg casino bonus codes…
Newest rtg casino bonus codes…
100 free spin…
100 free spin…
Free 1 hour play casinos…
Free 1 hour play casinos…
Brand new no deposit casino…
Brand new no deposit casino…
Casino slots…
Casino slots…
New no depoist poker march 2009 codes…
New no depoist poker march 2009 codes…
Rtg casino main codes for owners…
Rtg casino main codes for owners…
Free poker bonus diamond…
Free poker bonus diamond…
List of online free casino no deposit…
List of online free casino no deposit…
Royal casino las vegas free…
Royal casino las vegas free…
Casino online bonus codes free money…
Casino online bonus codes free money…
Bingo with 1 deposit to play…
Bingo with 1 deposit to play…
7 sultans code…
7 sultans code…
No deposit free cash…
No deposit free cash…
Welcome bonus no deposit sportbook…
Welcome bonus no deposit sportbook…
Party poker free promotion code…
Party poker free promotion code…
New blackjack casino codes…
New blackjack casino codes…
Bonus money without deposit…
Bonus money without deposit…
Online casino with no deposit bonus…
Online casino with no deposit bonus…
Worldwide freeplay casinos…
Worldwide freeplay casinos…
Jackpot party…
Jackpot party…
Free online slot machines super jackpot party…
Free online slot machines super jackpot party…
Virtual casino new free chip codes…
Virtual casino new free chip codes…
Free casino slot games no down loading…
Free casino slot games no down loading…
No deposit bingo bonuses uk…
No deposit bingo bonuses uk…
А у тебя посты никто не ворует c блога? А то меня вывели уже – тырят и тырят
здесь видел ет gamebulletin.ru
Привет! Я смотрю у тебя опыт в блоггерстве средненький, даже нормальный :) а я вот только начала =))
Если что смотри , заходи и звони!! а то скучно мне :’(
А лучше заходи и звони!!! ))
как говориться Чем примитивнее язык, тем примитивнее мышление человека, тем примитивнее становится
сам человек и тем легче таким управлять. Наш мир организован на инстинктах и психологии,
и нужно всегда брать от жизнь все как в сео, так в бизнесе, так и в любви.ВЕЗДЕ. Ненадо унывать никогда!
Нет нечего непозволительного. Славен героев путь в вальхаллу :)