1. Модель памяти Java
При выполнении программы виртуальная машина Java делит память, которую она управляет несколькими областями данных. Распределение этих областей данных показано на рисунке ниже:
Счетчик программы: небольшая область памяти, указывающая на в настоящее время выполняемый байт -код. Если поток выполняет метод Java, этот счетчик записывает адрес выполняемой инструкции виртуальной машины. Если собственный метод выполняется, значение калькулятора пусто.
Java Virtual Machine Stack: потоки являются частными, а их жизненный цикл соответствует потокам. Когда каждый метод будет выполнен, будет создана кадр стека для хранения информации, такой как локальные таблицы переменных, стеки операндов, динамические ссылки, выходы методов и т. Д.
Локальный стек методов: функции аналогичны стеку виртуальных машин, за исключением того, что стек виртуальных машин выполняет службы метода Java для виртуальной машины, в то время как локальный стек методов обслуживает используемый нативный метод.
Java Heap: Это самая большая часть памяти управления виртуальными машинами, разделяемая всеми потоками, эта область используется для хранения экземпляров объектов, и в этой области выделяются почти все объекты. Куча Java является основной областью утилизации памяти. С точки зрения утилизации памяти, поскольку большинство нынешних коллекционеров используют алгоритмы сбора поколений, куча Java также может быть подразделена на: новое поколение и старое поколение. Если он немного подразделяется, его можно разделить на пространство Eden, от пространства выживших, до пространства выживших и т. Д. В соответствии с спецификацией виртуальной машины Java, куча Java может находиться в физически недоступном пространстве, если она логически непрерывна.
Область метода: Как и Java, она используется различными потоками и используется для хранения данных, таких как информация класса, которая была загружена виртуальной машиной, всегда включенной, статическими переменными, код, составленный мгновенным компилятором.
Постоянный бассейн выполнения, постоянный бассейн выполнения, является частью области метода. В дополнение к классовой версии, полям, методам, интерфейсам и другой информации о описании, в файле класса также существует постоянный пул, который используется для хранения различных буквальных и символических ссылок, полученных в течение периода компиляции. Во время выполнения новые константы могут быть помещены в постоянный бассейн. Наиболее часто используемым является метод стажера () класса строки. Когда экземпляр строки вызывает стажера, Java обнаруживает, есть ли в постоянном пуле одинаковые константы строк Unicode. Если есть, он возвращает свою ссылку; Если нет, добавьте Unicode, равный строке экземпляра, и возвращает его ссылку.
2. Как определить мусоровый объект
Есть несколько экземпляров объекта, хранящихся в куче Java. До того, как коллектор мусора перерабатывает кучу, сначала необходимо определить, какие объекты все еще «живы», а какие - «мертвые», то есть объекты, которые не будут использоваться какими -либо средствами.
Цитата подсчет
Метод подсчета цитата прост в реализации и эффективно, и в большинстве случаев является хорошим алгоритмом. Принцип: добавьте справочный счетчик в объект. Всякий раз, когда существует место для ссылки на объект, счетчик увеличивается на 1. Когда эталон сбой, счетчик уменьшается на 1. Когда значение счетчика равно 0, это означает, что объект больше не используется. Следует отметить, что метод подсчета ссылок трудно решить проблему взаимной ссылки между объектами, а основные виртуальные машины Java не используют метод подсчета ссылок для управления памятью.
Алгоритм анализа доступности
Основная идея этого алгоритма состоит в том, чтобы искать вниз через серию объектов, называемых «корнями GC» в качестве отправной точки, начиная с этих узлов. Поиск по пути называется эталонной цепочкой. Когда объект не связан с корнями GC без какой -либо эталонной цепочки (в словах теории графика, он происходит от корней GC до этого объекта, который недоступен), доказано, что этот объект недоступен. Как показано на рисунке, хотя объекты 5, объект 6 и объект 7 связаны друг с другом, они недоступны для корней GC, поэтому они будут считаться, чтобы они были пригодными для переработки объектов.
На языке Java следующие объекты, которые можно использовать в качестве корней GC, включают:
Объект, на который ссылаются в стеке виртуальных машин (локальная таблица переменных в кадре стека).
Объект, на который ссылаются статический атрибут класса в области метода.
Объект, на который ссылаются постоянные в области метода.
Объекты, на которые ссылаются JNI (то есть общий нативный метод) в локальном стеке методов.
Теперь вопрос в том, будет ли алгоритм анализа доступности иметь круговую справочную проблему между объектами? Ответ - да, то есть не будет проблем с круглой ссылкой между объектами. ROOT GC - это специально определенная «начальная точка» вне графа объекта, и не может быть ссылается объекты на графике объектов.
Умереть или не умереть
Даже недоступные объекты в алгоритме анализа доступности не являются «не должны умереть». В настоящее время они временно находятся на стадии «испытательного срока». Чтобы по -настоящему объявить объект мертвым, он должен пройти как минимум два процесса маркировки: если объект обнаруживает, что нет эталонной цепочки, подключенной к корням GC после выполнения анализа доступности, он будет отмечен впервые и отфильтрован. Условие фильтрации заключается в том, необходимо ли этот объект выполнить метод Finapze (). Когда объект не перезаписывает метод finapze (), или метод Finapze () был вызван виртуальной машиной, виртуальная машина рассматривает оба случая как «нет необходимости выполнять». В программе вы можете перезаписать Finapze (), чтобы создать «захватывающий» процесс самосыпения, но это только один шанс.
/** * Этот код демонстрирует две точки: * 1. Объекты могут спасти себя, когда они GC. * 2. Существует только один шанс на самооценку, потому что метод Finapze () объекта будет автоматически называть только один раз системой максимум * @author zzm */ pubpc class finapzeescapegc {pubpc static finapzeescapegc save_hook = null; pubpc void isapve () {System.out.println ("Да, я все еще apve :)"); } @Override Protected void finapze () бросает throwable {super.finapze (); System.out.println ("Finapze Mehtod Caven!"); Finapzeescapegc.save_hook = это; } pubpc static void main (String [] args) бросает Throwable {save_hook = new finapzeescapegc (); // объект успешно экономит себя в первый раз save_hook = null; System.gc (); // Поскольку метод Finapze имеет низкий приоритет, пауза в течение 0,5 секунды, чтобы ждать его потока. Sleep (500); if (save_hook! = null) {save_hook.isapve (); } else {System.out.println ("Нет, я мертв :(");} // Следующий код точно такой же, как и выше, но на этот раз самоуничтожение потерпела неудачу. save_hook = null; System.gc (); // Потому что метод Finapze имеет низкий приоритет, он паус на 0,5 секунды до ожидания. Save_hook.isapve ();Результат работы:
Finapze Mehtod казнен! Да, я все еще apve :) Нет, я мертв :(
Поговорим о цитатах
Будь то оценка количества ссылок объекта с помощью алгоритма подсчета ссылок или определение того, достигается ли эталонная цепочка объекта с помощью алгоритма анализа доступности, определяя, связано ли выживание объекта с «ссылкой». Перед JDK 1.2 определение ссылок в Java было очень традиционным: если значение, хранящееся в данных ссылочного типа, представляет собой начальный адрес другой части памяти, говорится, что эта часть памяти представляет собой ссылку. После JDK 1.2 Java расширила концепцию ссылки и разделенные ссылки на четыре типа: сильная ссылка, мягкая ссылка, слабая ссылка и призрачная ссылка. Сила этих четырех типов эталона постепенно ослабевалась по очереди.
• Сильная цитата относится к ссылкам, которые распространены в коде программы, такие как «Object obj = new Object ()». Пока сильная цитата все еще существует, сборщик мусора никогда не будет перерабатывать ссылочный объект.
• Мягкие ссылки используются для описания некоторых полезных, но не необходимых объектов. Для мягких ссылок, связанных с объектами, эти объекты будут перечислены в области переработки для второй переработки, прежде чем система собирается запустить исключение переполнения памяти. Если для этой переработки недостаточно памяти, будет брошено исключение переполнения памяти. После JDK 1.2 класс Softreference предоставляется для реализации мягких ссылок.
• Слабые ссылки также используются для описания несущественных объектов, но их сила слабее, чем мягкие ссылки. Объекты, связанные со слабыми ссылками, могут выжить только до тех пор, пока не произойдет следующая коллекция мусора. Когда коллекционер мусора работает, объекты, которые связаны только со слабыми ссылками, собираются независимо от того, является ли текущая память достаточной. После JDK 1.2 класс ShideReference предоставляется для реализации слабых ссылок.
• Цитаты на пустоты также называются кавычками -призраками или призрачными цитатами, и они являются самыми слабыми отношениями цитирования. Есть ли у объекта виртуальная ссылка вообще не окажет никакого влияния на время выживания, и при этом не будет возможно получить экземпляр объекта с помощью виртуальной ссылки. Единственная цель создания виртуальных справочных ассоциаций для объекта - это получить системное уведомление, когда объект переработан коллекционером. После JDK 1.2 класс PhantomReference предоставляется для реализации виртуальных ссылок.
Пример использования мягкого эталона:
пакет jvm; import java.lang.ref.softreference; класс Node {pubpc String msg = "";} pubpc class hello {pubpc static void main (string [] args) {node node1 = new node (); // Сильный эталонный node1.msg = "node1"; softreference <node> node2 = new Softreference <node> (node1); // Soft Supper Node2.get (). MSG = "node2"; System.out.println (node1.msg); System.out.println (node2.get (). Msg);}}Результатом вывода:
Node2node2
3. Типичный алгоритм сбора мусора
1.mark-sweep (Mark-Clear) алгоритм
Это самый простой алгоритм сбора мусора. Причина, по которой он, как говорят, является самой простой, заключается в том, что проще всего реализовать и самая простая идея. Алгоритм очистки от марки делится на два этапа: этап маркировки и стадия очистки. Задача стадии маркировки состоит в том, чтобы отметить все объекты, которые необходимо переработать, и этап очистки состоит в том, чтобы переработать пространство, занятое отмеченными объектами. Конкретный процесс показан на рисунке ниже:
Из рисунка можно легко увидеть, что алгоритм очистки от марки легче реализовать, но существует серьезная проблема, что легко генерировать фрагменты памяти. Слишком много фрагментов может привести к неспособности найти достаточно места при распределении места для больших объектов в последующем процессе, и заранее вызвать новое действие сбора мусора.
2. Копирование алгоритма
Чтобы решить недостатки алгоритма Mark-Sweep, был предложен алгоритм копирования. Он делит доступную память на два часа одинакового размера по емкости, используя только один кусок за раз. Когда этот кусок памяти используется, скопируйте все еще живой объект в другой кусок, а затем очистите используемое пространство памяти одновременно, чтобы проблемы с фрагментацией памяти не возникнут. Конкретный процесс показан на рисунке ниже:
Хотя этот алгоритм прост в реализации, эффективен для запуска и нелегко генерировать фрагментацию памяти, его дорого используют пространство памяти, потому что память, которая может быть использована, уменьшается до половины исходного.
Очевидно, что эффективность алгоритма копирования во многом связана с количеством выживших объектов. Если есть много выживших объектов, эффективность алгоритма копирования будет значительно снижена.
3. Алгоритм Mark-Compact (Mark-Collation)
Чтобы решить недостатки алгоритма копирования и в полной мере использовать пространство памяти, предлагается алгоритм маркировки. Алгоритм отмечает то же самое, что и Mark-Sweep, но после завершения отметки он не вычитывает непосредственно утилизируемые объекты, а перемещает все живые объекты на один конец, а затем очищает память за пределами конечной границы. Конкретный процесс показан на рисунке ниже:
4. Алгоритм сбора поколений
Алгоритм коллекции поколений в настоящее время используется большинством коллекционеров мусора JVM. Его основная идея состоит в том, чтобы разделить память на несколько разных регионов в зависимости от жизненного цикла выживания объекта. Вообще говоря, область кучи разделена на старое поколение и молодое поколение. Характеристикой старого поколения является то, что только небольшое количество объектов необходимо переработать каждый раз, когда собирается мусор, в то время как характеристика нового поколения заключается в том, что большое количество объектов необходимо переработать каждый раз, когда собирается мусор. Тогда наиболее подходящий алгоритм сбора может быть принят в соответствии с характеристиками разных поколений.
В настоящее время большинство коллекционеров мусора принимают алгоритм копирования для нового поколения, потому что в новом поколении большинство объектов должны быть переработаны каждый раз, то есть количество операций, которые необходимо скопировать, невелико, но на самом деле пространство нового поколения не разделено в соответствии с соотношением 1: 1. Вообще говоря, новое поколение делится на более широкое пространство Eden и два меньших пространства выживших (обычно 8: 1: 1). Каждый раз, когда используется пространство Эдема и одно из мест для выживших при переработке, объекты, которые все еще выживают в Эдема и выживших, копируются в другое пространство выживших, а затем Эдем и только что использованные пространства выживших и выживших, которые только что были использованы.
Поскольку старость заключается в том, что только небольшое количество объектов перерабатывается каждый раз, обычно используется алгоритм маркировки.
Приведенный выше краткий анализ модели памяти Java и коллекции мусора - это весь контент, которым я делюсь с вами. Я надеюсь, что вы можете дать вам ссылку, и я надеюсь, что вы сможете поддержать Wulin.com больше.