Почему фиксированный максимальный размер кучи Java? - PullRequest
32 голосов
/ 21 января 2010

Это - это , а не возможно , чтобы увеличить максимальный размер кучи Java после запуска виртуальной машины. Каковы технические причины для этого? Зависят ли алгоритмы сбора мусора от наличия фиксированного объема памяти для работы? Или это из соображений безопасности, чтобы приложение Java не могло DOS'ить другие приложения в системе, потребляя всю доступную память?

Ответы [ 5 ]

23 голосов
/ 21 января 2010

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

Даже если не все используются сразу, адресное пространство для всей кучи резервируется при запуске. Если он не может зарезервировать достаточно большой непрерывный блок адресного пространства для значения -Xmx, которое вы передаете, он не запустится. Вот почему трудно выделить> 1,4 ГБ кучи в 32-разрядной Windows - потому что трудно найти непрерывное адресное пространство такого размера или больше, поскольку некоторые библиотеки DLL загружаются в определенных местах, фрагментируя адресное пространство. На самом деле это не проблема, когда вы переходите на 64-разрядную версию, поскольку адресного пространства намного больше.

Это почти наверняка по соображениям производительности. Я не смог найти потрясающую ссылку, подробно описывающую это, но вот довольно хорошая цитата Питера Кесслера ( полная ссылка - обязательно прочитайте комментарии), которую я нашел при поиске. Я считаю, что он работает над JVM в Sun.

Причина, по которой нам нужна непрерывная память область для кучи в том, что у нас есть куча побочных структур данных, которые индексируется (масштабируется) смещениями от начало кучи. Например, мы отслеживать обновления объекта ссылки с «массив меток карты», имеющий один байт за каждые 512 байтов кучи. Когда мы сохранить ссылку в куче у нас есть отметить соответствующий байт в массив карт Мы прямо сдвигаем адрес назначения магазина и используйте это для индексации массива карт. Веселые решения арифметических игр вы не могу сделать в Java, что вы получите (есть играть :-) в C ++.

Это было в 2004 году - я не уверен, что изменилось с тех пор, но я почти уверен, что оно все еще сохраняется. Если вы используете такой инструмент, как Process Explorer, вы увидите, что виртуальный размер (добавьте столбцы виртуального размера и памяти частного размера) приложения Java включает в себя общий размер кучи (плюс, несомненно, другое необходимое пространство) с точки запуска даже если память, «используемая» процессом, не будет где-то рядом, пока куча не начнет заполняться ...

8 голосов
/ 21 января 2010

Исторически для этого ограничения была причина, которая не позволяла апплетам в браузере поглощать всю пользовательскую память. Виртуальная машина Microsoft, которая никогда не имела такого ограничения, фактически позволяла делать это, что могло привести к некоторой атаке типа «отказ в обслуживании» на компьютер пользователя. Лишь год назад Sun представила в виртуальной машине 1.6.0 Update 10 способ, позволяющий апплетам указывать, какой объем памяти они хотят (ограниченный определенной фиксированной долей физической памяти), вместо того, чтобы всегда ограничивать их до 64 МБ даже на компьютерах которые имеют 8 ГБ или более.

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

4 голосов
/ 21 января 2010

Я думаю, что короткий, язвительный ответ заключается в том, что Sun не нашла того, что стоит времени и затрат на разработку.

Наиболее убедительный вариант использования такой функции на настольном компьютере, IMO, и Java всегда была катастрофой для настольного компьютера, когда речь шла о механизме запуска JVM. Я подозреваю, что те, кто больше всего думают об этих проблемах, как правило, сосредотачиваются на стороне сервера и просматривают любые другие детали, которые лучше оставить родным упаковщикам. Это неудачное решение, но оно должно быть лишь одним из пунктов при выборе правильной платформы для приложения.

3 голосов
/ 21 января 2010

Мне кажется, что это связано с управлением памятью относительно других приложений, работающих в операционной системе.

Если вы установите максимальный размер кучи, например, на объем оперативной памяти в блоке, вы фактически позволите виртуальной машине решать, какой объем памяти ей требуется (до этого предела). Проблема заключается в том, что виртуальная машина может эффективно нанести вред машине, на которой она работает, потому что она займет всю память в блоке, прежде чем решит, что ей нужно собрать мусор.

Когда вы указываете максимальный размер кучи, то, что вы говорите виртуальной машине, вы можете использовать этот объем памяти, прежде чем вам нужно будет начать сборку мусора. Вы не можете иметь больше, потому что если вы возьмете больше, другие приложения, работающие на коробке, замедлятся, и вы начнете переключаться на диск, если будете использовать больше, чем это.

Также имейте в виду, что это два значения по отношению к памяти, то есть «текущий размер кучи» и «максимальный размер кучи». Текущий размер кучи - это объем памяти, который используется в данный момент, и, если ему требуется больше, он может изменить размер кучи, но не может изменить размер кучи выше значения максимального размера кучи.

2 голосов
/ 21 января 2010

Из советов по настройке производительности IBM (поэтому может не иметь прямого отношения к виртуальным машинам Sun)

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

JVM имеет пороговые значения, которые она использует для управления хранилищем JVM. Когда пороговые значения достигнуты, сборщик мусора вызывается для освобождения неиспользуемого хранилища. Следовательно, сборка мусора может привести к значительному снижению производительности Java. Прежде чем изменять начальный и максимальный размеры кучи, вы должны рассмотреть следующую информацию: В большинстве случаев вы должны установить максимальный размер кучи JVM, который будет выше начального размера кучи JVM. Это позволяет JVM эффективно работать в течение периодов нормального, устойчивого состояния в пределах начальной кучи, а также эффективно работать в периоды большого объема транзакций, расширяя кучу до максимального размера кучи JVM. В некоторых редких случаях, когда требуется абсолютная оптимальная производительность, вы можете указать одно и то же значение для начального и максимального размера кучи. Это устранит некоторые издержки, возникающие, когда JVM необходимо расширить или сократить размер кучи JVM. Убедитесь, что область достаточно велика, чтобы вместить указанную кучу JVM. Остерегайтесь слишком большого начального размера кучи. Хотя большой размер кучи изначально повышает производительность за счет задержки сборки мусора, большой размер кучи в конечном итоге влияет на время отклика, когда сборка мусора в конечном итоге запускается, поскольку процесс сбора занимает больше времени.

Итак, я думаю, причина того, что вы не можете изменить значение во время выполнения, состоит в том, что оно может не помочь: либо у вас достаточно места в куче, либо нет. Как только вы закончите, цикл GC будет запущен. Если это не освобождает место, вы все равно напичканы. Вам нужно будет перехватить исключение OutOfMemoryException, увеличить размер кучи и повторить расчет, надеясь, что на этот раз у вас будет достаточно памяти.

Как правило, виртуальная машина не будет использовать максимальный размер кучи, если вам это не нужно, поэтому, если вы считаете, что вам может потребоваться увеличить объем памяти во время выполнения, вы можете просто указать большой максимальный размер кучи.

Я признаю, что все это немного неудовлетворительно и кажется немного ленивым, поскольку я могу представить разумную стратегию сбора мусора, которая бы увеличивала размер кучи, когда GC не может освободить достаточно места. Может ли мое воображение перевести на реализацию высокопроизводительных GC - другой вопрос;)

...