Устройство памяти Java-процесса.

Если вы читаете эту статью, значит вы уже работаете с Java и не хотите останавливаться на простом знании синтаксиса языка, стандартных библиотек и популярных Java-фреймворков — вы действительно хотите знать, как работает JVM, как выделяется память и происходит процесс сборки мусора.

В данной статье я хочу познакомить вас с устройством памяти в Java. Отсюда вы узнаете, где в Java хранятся локальные переменные, создаются объекты и как регулировать размер различных областей памяти для Java-процесса.

Итак, давайте сначала взглянем из каких областей состоит память, выделяемая JVM  для вашей программы.

Java Heap.

А теперь давайте поподробнее. Память под объекты, которые вы создаете в своем приложении JVM выделяет из области, называемой кучей (heap),  которая разделена на части — так называемый Young Generation и Old Generation. Зачем делить всю память на две части?

Более подробно мы поговорим об этом в статье, посвященной механизму сборки мусора в JVM. Сейчас я объясню это совсем коротко: сборка мусора в Java основывается на так называемой слабой гипотезе о поколениях, которая гласит о том, что большинство создаваемых в программе объектов умирают рано: это всевозможные локальные переменные, временные объекты, которые быстро отживают свое и больше не нужны. Garbage collector’у (сборщику мусора) нужно подобрать их в одном из следующих проходов и освободить память.

Изначально все объекты находятся в Young Generation. Но другие объекты (меньшая их часть), которые могут существовать длительное время или на протяжении жизни всего приложения, не нужно удалять. На эти объекты постоянно нужны «живые» ссылки. Сборщик мусора не удаляет их до тех пор, пока ссылки на них еще существуют. Они переживают одну за другой сборку мусора и наконец перемещаются во вторую часть Java-Heap’а — Old Generation, откуда с гораздо меньшей вероятностью будут когда-либо удалены (конечно, все зависит от специфики вашей программы и размера кучи, см.ниже).

Что делать, если вы получили Out of Memory Error: java heap space и уверены в том, что ваша программа не страдает от утечек памяти или неэффективного кода?

Вы можете регулировать размер кучи, запустив вашу программу со следующими параметрами: -Xms(минимальный размер Java heap’а) или —Xmx(максимальный размер Java heap’a).

Permanent Generation.

При первой загрузке вашего класса JVM создает объект Class. Это метаинформация, необходимая для создания новых объектов в Java, хранится как раз в области памяти,называемой Permanent Generation. Код ваших методов также хранится здесь, как и все статические переменные и методы.

И еще: теперь, получив в процессе выполнения вашей программы исключение Out of Memory Error: PermGen space, вы будете знать, размер какой именно области памяти Java-процесса надо увеличить. Для этого используйте параметры запуска программы: —XX:PermSize(начальный размер PermGen) или -XX:MaxPermSize(максимальный размер PermGen).

Java Stack.

Java — это стековая виртуальная машина. Надеюсь, что вам не нужно объяснять, что такое стек. Если вы все же нуждаетесь в том, чтобы освежить свои знания, обратитесь к этой статье.

Итак,  JVM загружает в стек все локальные переменные и параметры вызываемых методов. При дальнейшем выполнении программы она их оттуда забирает, осуществляет нужные действия и кладет результат обратно в стек или просто извлекает следующий операнд. Также нужно знать,что стек делится на несколько областей, соответствующих каждому выполняемому потоку в вашей программе.

Если всем потокам в вашей программе нужно больше памяти и вы хотите избежать StackOverflowError, то имеет смысл увеличить размер стека, используя параметр -Xss. Отдельно следует уделить внимания потокам,в которых возможны рекурсивные вызовы методов. Также, для более точной регулировки размера доступной памяти для каждого потока, можно воспользоваться одним из конструкторов класса Thread(ThreadGroup group, Runnable target, String name, long stackSize), что может оказаться более разумным решением. Последний параметр stackSize говорит сам за себя.

Я сказал, что в стеке хранятся все локальные переменные и параметры. Но это не совсем так. Для объектов хранятся только ссылки на них, в то время как сами объекты находятся в куче. К слову, это уже не совсем так благодаря функции Escape Analysis из Java 6: те объекты, которые являются исключительно локальными и не возвращаются за пределы выполняемого метода также сохраняются в стеке. Это сделано для того, чтобы сборщик мусора впоследствии мог их быстро удалить.

Заключение.

Итак, мы познакомились с тем, как же JVM «под капотом», работает с памятью, выделяемой для создаваемых объектов,где хранятся статические переменные и данные для каждого потока. Жду ваших комментариев и пожеланий. Успехов в программировании!

2 комментария

  1. Paul Ответить

    Далеко не все спешат обновляться и полным полно проектов на допотопных версиях

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *