В стартовых параметрах Java есть два параметра -Xmx и -Xms, которые отвечают за то, какой объем heap вы хотите выделить вашему приложению при старте (-Xms), и какой максимальный объем памяти (-Xmx) вы хотите выделить для программы за все время ее работы.
Опыт показывает, что для улучшения производительности крупного «тяжелого» Java-приложения лучше всего этим двум параметрам давать одно и то же значение. Как выбрать конкретное значение, рассказывается в другой статье. В данной заметке я просто приведу несколько аргументов в пользу этой стратегии.
Если выставить одно и то же значение параметрам -Xmx и -Xms, например, -Xmx8g и -Xms8g, то при старте Java-приложения JVM запрашивает и получает от операционной сразу требуемый объем памяти в 8 Гб.
За все время работы может все 8 Гб памяти и не будут использованы. Может так случится, что все 8 Гб понадобятся и будут использованы только в где-то через несколько часов работы приложения. Захват 8 Гб памяти, который нам сейчас не нужен выглядит расточительством. Какие же преимущества нам это дает?
Более быстрый старт
Если -Xms выставлен на слишком малое значение, Java-приложение при старте начнет быстро ощущать недостаток памяти, значит часть времени при старте будет тратиться на сборку мусора и аллоцирование все новых и новых новых объемов памяти. Это замедлит старт системы, а во многих случаях быстрый стоп-рестарт системы может быть критически важным.
Трата времени на аллокацию памяти
Допустим приложение благополучно стартовало и работает уже несколько часов. В определенный момент времени наступает определенное важное событие, которое приводит к созданию множества новых объектов в heap. Если текущий объем heap недостаточен для размещения в нем новых объектов, JVM будет срочно аллоцировать новые участки памяти. То есть в критический момент, когда важна каждая микросекунда, JVM будет занята не обработкой критической бизнес-логики, а на переговоры с операционной системой по выделению все новых и новых участков памяти. Разумеется, это скажется на производительности приложения, причем именно в тот момент, когда производительность наиболее важна.
Конкуренция с другими приложениями
Если параллельно на системе работает несколько приложений, то приложение, которое будет требовать все больше и больше объемов памяти, может быть молча убито операционной системой. Это может произойти по той причине, что свободная память закончится и операционная система не сможет удовлетворить запросы приложения.
Задавая разные значения для -Xmx и -Xms, вы как раз и подвергаете свое приложение такому риску. Если же параметры выставлены на одинаковое значение, вся требуемая память будет выделена приложению с самого начала при старте, и значит к операционной системы от вашего приложения не будут поступать запросы на новые участки памяти, а в случае «истощения запасов» памяти будет «убито» какое-то другое приложение.
На заметку
Чтобы посмотреть все параметры JVM, начинающиеся на -X, наберите в командной строке:
$ java -X
Итоги
Помимо параметров -Xmx и -Xms есть и другие параметры, управляющие различными аспектами heap: например, распределением heap между young generation и old generation, размерами секций young generation. Все эти параметры оказывают значительное влияние на производительность, а значения для них подбираются эмпирически с учетом конкретного Java-приложения. Кроме того, разные сборщики мусора имеют свои особенные параметры, характерные для специфики их работы.
Тема настройки сборщика мусора неисчерпаема и в этом блоге я не раз еще вернусь к ней.