пятница, 11 ноября 2011 г.

finalize() и сборщик мусора

Все знают и помнят о важности инициализации, но многие забывает о значимости приборки за собой. Конечно, в Java есть сборщик мусора(garbage collector), который выполняет за вас грязную работу и освобождает память от ненужных объектов. Но если, например, ваш объект выделяет память каким-нибудь специфическим способом(без использования new), то тут сборщик мусора вам не поможет. Для таких случаев в Java и предусмотрен метод finalize(), который вы можете определить в вашем классе. Когда сборщик мусора захочет освободить память, занимаемую ненужным объектом, он сначала вызовет метод finalize() этого объекта, и только потом удалит сам объект. Но(!) следует помнить, что ваши объекты могут быть и не переданы сборщику мусора.

Так что если перед тем, как объект станет ненужным, необходимо выполнить некоторые завершающие действия, то делайте это собственноручно, не стоит полагаться на finalize().
Может случиться так, что память объекта никогда не будет освобождена, потому что программа даже не приблизиться к точке критического расхода ресурсов. Помните, что ни сборка мусора, ни финализация не гарантированы.
И немного об этом загадочном сборщике мусора.
Как бы ни странно это звучало, но использование сборщика мусора даёт немалый эффект по ускорению создания объектов. Любой существующий объект прослеживается до ссылки находящейся в стеке или статической памяти. Таким образом, если начать проверку со стека и статического хранилища, мы обязательно доберемся до всех используемых объектов. Для каждой найденной ссылки надо взять объект, на который она указывает, и отследить все ссылки этого объекта, при этом выявляются все другие объекты, на которые они указывают, и так далее. Таким образом будет проверена вся структура ссылок, берущая начало в стеке и статической памяти. Каждый объект, обнаруженный в ходе поиска, всё ещё используется. Работа программы временно приостанавливается, затем все найденные используемые объекты копируются из одной кучи в другую, а мусор остается в первой. При копировании объектов в новую кучу они размещаются в виде компактной непрерывной цепочки. При копировании все ссылки переопределяются.
Существует два фактора, из-за которых такой механизм обладает низкой эффективностью. Во-первых, существует две кучи, и вы перекидываете всё то туда, то сюда между двумя кучами, и при этом половина памяти тратится впустую. Во-вторых, копирование в фазе стабильной работы программы, когда отходов становится мало, очень невыгодно. Некоторые JVM определяют, что новых отходов появляется очень мало, и переключаются в другой режим сборки мусора. Тут точно так же находятся используемые и неиспользуемые объекты, но копирования в другую кучу не происходит, и если сборщик мусора захочет уплотнить фрагментированную кучу, то делается это перемещением объектов внутри неё.
Виртуальная машина постоянно следит за эффективностью сборки мусора, и, если надо, переключает режим. Таким образом, куча после сборки мусора достаточно фрагментированна, и выделение новой памяти происходит не поиском свободного места, а смещением указателя начала кучи, почти как в стеке.

Комментариев нет:

Отправить комментарий

Примечание. Отправлять комментарии могут только участники этого блога.