11.07.2016

Еще раз о java памяти и сборке мусора



Давайте начнем с простых вещей,  с типов языка java, существуют в нем  два типа данных примитивы и ссылочные типы или точнее сказать указатели на память. Для примера:

int a = 10; // примитивный тип
Person person = new Person(“Vit”); //сыллочный тип

 Особенность типов языка java  в том что в не зависимости от  JVM и платформы на которой JVM  крутится,  будь то Linux или Windows  размерность типов остается постоянной.  В зависимости от разрядности системы, указатели на память могут быть или 32-разрядными или 64-разрядными. Когда полю объекта ссылочного типа присваивается другой объект ссылочного типа, обычно копируется только ссылка на сам объект и при этом не создается новый объект. Рассмотрим наш пример:

Person person = new Person(“Vit”); //создаем ссылочный тип
Person person2 =person; // скопировали ссылку на объект Person(“Vit”); теперь на один объект ссылаются две переменные ссылочного типа person2 и person.
person2.setName(“Oleg”);//  и если мы изменим значение имени в ссылке person2 System.out.println(person.getName);// то при выводе объекта person  мы получим значение Oleg т.к. мы работаем с одним и тем же объектом

Продолжим,  любая программа на языке java по умолчанию запускается в главном потоке  (Thread), потоков  вы можете запустить столько, сколько вам нужно.  Поток работает с двумя видами памяти JVM: Стек и Куча.  Куча – это разделяемая или общая память где создаются объекты на которые указывают ссылочные переменные.  Стек – это место где создаются локальные переменные. Локальные переменные-примитивы  хранят свое значение  прямо в стеке, а локальные переменные-ссылочного типа будут хранить в стеке только  указатель на объект в Куче.  Любой поток имеет свой собственный стек, а куча одна для всех потоков смотрите рисунок.



Сделаем небольшое отступление, из предыдущего раздела можно сделать вывод, что ко всем ссылочным типам обязательно нужно применять синхронизацию доступа к объекту в Куче, т.е. если   доступ к одному и тому же объекту в Куче имеют разные потоки. Это правило не относится к локальным ссылочным объектам, т. к. область видимости локальных объектов в куче ограничивается только одним потоком, и по этому они не могут быть видны в другом потоке. В языке java  Кучей называется  Java Heap.  И так Java Heap – это память jvm  выделяемая во время запуска, где хранятся и живут все создаваемые нами объекты, все нелокальные переменные, массивы и т. д. Обрабатывается он, специальным менеджером памяти автоматически, который называют garbage collector (GC) - сборщиком мусора. Вы можете попросить GC только выделить память, когда вы создаете объект   ключевым словом  new,  а  сборку мусора - освобождение памяти он делает автоматически. Хотя есть два метода  System.gc() и Runtime.gc() которые, просят “GC  запуститься”, но на них нельзя полагаться, поскольку другие более приоритетные потоки могут отложить их выполнение.  JVM  поставляется с несколькими типами GC, которые можно выбрать и настроить под свои нужды посредством параметров  которые передаются при запуске jvm. Бывают случаи когда не хватает памяти процессу JVM,  тогда  возникает ошибка java.lang.OutOfMemoryError, об этой ошибке можно подробней почитать здесь, так же я вам советую прочитать статью о виртуальной машине Java,   хотя информация в них уже немного устарела. А устарела она в том, что  с 8 версии jvm, PermSize уже не используется и его заменили областью памяти которая называется class metadata. До 8 версии jvm, PermSize была составной частью Java Heap.  И как сказано в статьях, там хранятся все метаданные загруженные  ClassLoader’ом , еще эту память называют  словом  Method Area. Пожалуйста ознакомтесь с моей статьей о памяти которой обладает процесс jvm.  Я думаю с вас достаточно пока этой информации. У меня есть планы написать  в следующих статьях о разных типах GC и их настройке. А на сегодня я думаю вам хватит этой информации которую я вам дал по ссылкам, не спеша переварите её.