Java ограничение памяти linux

Обновлено: 03.07.2024

У меня есть проблема с приложением Java, работающим под управлением Linux.

Когда я запускаю приложение, используя максимальный размер кучи по умолчанию (64 MB), я вижу, что с помощью приложения tops ему выделено 240 MB виртуальной памяти. Это создает некоторые проблемы с некоторым другим программным обеспечением на компьютере, которое относительно ограничено ресурсами.

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

Есть ли в любом случае, что я могу настроить виртуальную память, используемую для процесса Java под Linux?

Правка 1: проблема не в куче. Проблема в том, что если я задаю кучу 128 MB, например, все равно Linux выделяет 210 MB виртуальной памяти, которая не нужна никогда.**

Правка 2: Использование ulimit -v позволяет ограничить объем виртуальной памяти. Если заданный размер меньше 204 MB, то приложение не будет работать, даже если ему не нужно 204 MB, а только 64 MB. Поэтому я хочу понять, почему Java требует так много виртуальной памяти. Можно ли это изменить?

Правка 3: в системе работает несколько других приложений, которые встроены. И система действительно имеет ограничение виртуальной памяти (из комментариев, важная деталь).

Я работаю во встроенной среде, где ресурсы довольно ограничены. Мы пытаемся использовать node.js, который хорошо работает, но обычно потребляет около 60 мегабайт виртуальной памяти (реальная используемая память составляет около 5 мегабайт.) Учитывая наши ограничения, это слишком много виртуальной.

Я пытаюсь глубоко понять управление виртуальной памятью в OS Linux. Я действительно не понимаю, как OS определяет размер VM для процесса. Я знаю, что 32-битный x86 OS может дать до 3 GB адресного пространства виртуальной машины. Всегда ли это так ? В моем случае у меня есть около 110 MB.

Это была давняя жалоба с Java, но она в значительной степени бессмысленна и обычно основана на просмотре неправильной информации. Обычная фраза звучит примерно так: "Hello World on Java занимает 10 мегабайт! Зачем ему это нужно?" Ну, вот способ сделать Hello World на 64-bit JVM претендовать на то, чтобы занять более 4 гигабайт . по крайней мере, одной формой измерения.

На Linux верхняя команда дает вам несколько разных чисел для памяти. Вот что он говорит о примере Hello World:

  • VIRT-это пространство виртуальной памяти: сумма всего, что находится на карте виртуальной памяти (см. Это в значительной степени бессмысленно, за исключением тех случаев, когда это не так (см.
  • RES-это размер резидентного набора: количество страниц, которые в данный момент находятся в RAM. Почти во всех случаях это единственное число, которое вы должны использовать, говоря "too big.", но это все еще не очень хорошее число, особенно когда речь идет о Java.
  • SHR - это объем резидентной памяти, совместно используемой другими процессами. Для процесса Java это обычно ограничивается общими библиотеками и отображенными в памяти JARfiles. В этом примере у меня был запущен только один процесс Java, поэтому я подозреваю, что 7k-это результат библиотек, используемых OS.
  • SWAP не включен по умолчанию и не отображается здесь. Он указывает объем виртуальной памяти, которая в данный момент находится на диске, независимо от того, находится ли она на самом деле в пространстве подкачки . OS очень хорошо справляется с сохранением активных страниц в RAM, и единственные средства для замены-это (1) купить больше памяти или (2) уменьшить количество процессов, поэтому лучше игнорировать это число.

Ситуация с Windows Task Manager немного сложнее. Под Windows XP есть столбцы "Memory Usage" и "Virtual Memory Size", но официальная документация умалчивает о том, что они означают. Windows Vista и Windows 7 добавляют дополнительные столбцы ,и они фактически документированы. Из них наиболее полезным является измерение "Working Set"; оно примерно соответствует сумме RES и SHR на Linux.

Виртуальная память, потребляемая процессом, - это общая сумма всего, что находится в карте памяти процесса. Это включает в себя данные (например, кучу Java), а также все общие библиотеки и файлы с отображением памяти, используемые программой. На Linux вы можете использовать команду pmap , чтобы увидеть все вещи, отображенные в пространстве процесса (с этого момента я буду ссылаться только на Linux, потому что это то, что я использую; я уверен, что есть эквивалентные инструменты для Windows). Вот отрывок из карты памяти программы "Hello World"; вся карта памяти имеет длину более 100 строк, и нет ничего необычного в том, чтобы иметь список из тысячи строк.

Краткое объяснение формата: каждая строка начинается с адреса виртуальной памяти сегмента. Далее следуют размер сегмента, разрешения и источник сегмента. Этот последний элемент является либо файлом, либо "anon", что указывает на блок памяти, выделенный через mmap .

Начиная с самого верха, мы имеем

  • Загрузчик JVM (то есть программа, которая запускается при вводе java ).) очень мал; все, что он делает, это загружается в общие библиотеки, где хранится реальный код JVM.
  • Куча блоков anon, содержащих кучу Java и внутренние данные. Это Sun JVM, поэтому куча разбивается на несколько поколений, каждое из которых является своим собственным блоком памяти. Обратите внимание, что JVM выделяет пространство виртуальной памяти на основе значения -Xmx ; это позволяет ему иметь непрерывную кучу. Значение -Xms используется внутренне, чтобы сказать, какая часть кучи составляет "in use" при запуске программы, и вызвать сборку мусора по мере приближения к этому пределу.
  • Сопоставленный с памятью JARfile, в данном случае файл, содержащий "JDK classes.", когда вы сопоставляете память с JAR, вы можете получить доступ к файлам внутри него очень эффективно (по сравнению с чтением его с самого начала каждый раз). Sun JVM будет отображать в памяти все JARs на classpath; если ваш код приложения должен получить доступ к JAR, вы также можете отобразить его в памяти.
  • Данные по каждому потоку для двух потоков. Блок 1M-это стек потоков. У меня не было хорошего объяснения для блока 4k, но @ericsoe идентифицировал его как "защитный блок": он не имеет разрешений на чтение/запись, поэтому вызовет ошибку сегмента при доступе, и JVM поймает это и переведет его в StackOverFlowError . Для реального приложения вы увидите десятки, если не сотни таких записей, повторяющихся на карте памяти.
  • Одна из общих библиотек, которая содержит фактический код JVM. Их несколько.
  • Общая библиотека для стандартной библиотеки C. Это всего лишь одна из многих вещей, которые загружает JVM и которые не являются строго частью Java.

Общие библиотеки особенно интересны: каждая общая библиотека имеет по крайней мере два сегмента: сегмент только для чтения, содержащий код библиотеки, и сегмент чтения-записи, содержащий глобальные данные для каждого процесса для библиотеки (я не знаю, что такое сегмент без разрешений; я видел его только на x64 Linux). Доступная только для чтения часть библиотеки может быть разделена между всеми процессами, использующими библиотеку; например, libc имеет 1.5M пространства виртуальной памяти,которое может быть разделено.

Карта виртуальной памяти содержит много вещей. Некоторые из них доступны только для чтения, некоторые являются общими, а некоторые выделяются, но никогда не трогаются (например, почти все 4 ГБ кучи в этом примере). Но операционная система достаточно умна, чтобы загружать только то, что ей нужно, поэтому размер виртуальной памяти в значительной степени не имеет значения.

Размер виртуальной памяти важен, если вы работаете в 32-разрядной операционной системе, где вы можете выделить только 2 ГБ (или, в некоторых случаях, 3 ГБ) адресного пространства процесса. В этом случае вы имеете дело с ограниченным ресурсом, и, возможно, вам придется пойти на компромисс, например, уменьшить размер кучи, чтобы сопоставить большой файл с памятью или создать много потоков.

Но, учитывая, что машины 64-bit вездесущи, я не думаю, что пройдет много времени, прежде чем размер виртуальной памяти станет совершенно неуместной статистикой.

Размер резидентного набора - это та часть пространства виртуальной памяти, которая на самом деле находится в RAM. Если ваш RSS становится значительной частью вашей общей физической памяти, возможно, пришло время начать беспокоиться. Если ваш RSS растет, чтобы занять всю вашу физическую память, и ваша система начинает меняться местами, давно пора начать беспокоиться.

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

Если вы не меняетесь местами, не слишком заботьтесь о том, что говорит вам различная статистика памяти. С оговоркой, что постоянно растущий RSS может указывать на какую-то утечку памяти.

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

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

Существует известная проблема с Java и glibc >= 2.10 (включает в себя Ubuntu >= 10.04, RHEL >= 6).

Лекарство состоит в том, чтобы установить эту переменную env.:

Если вы используете Tomcat, вы можете добавить его в файл TOMCAT_HOME/bin/setenv.sh .

Для Docker добавьте это к Dockerfile

известно, что резидентная память ползет подобно утечке памяти или фрагментации памяти.

найдите MALLOC_ARENA_MAX в Google или SO для получения дополнительных ссылок.

Возможно, вы захотите настроить и другие параметры malloc для оптимизации низкой фрагментации выделенной памяти:

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

У вас есть еще несколько вариантов, которые вы можете попробовать ограничить объем памяти вашего JVM. Это может уменьшить объем виртуальной памяти:

-XX:ReservedCodeCacheSize=32m зарезервированный размер кэша кода (в байтах) - максимальный размер кэша кода. [Solaris 64-bit, amd64, and-server x86: 48m; in 1.5.0_06 и ранее, Solaris 64-bit и and64: 1024m.]

-XX:MaxPermSize=64м размер постоянного поколения. [5.0 и новее: 64 bit VMs масштабируются 30% больше; 1.4 amd64: 96m; 1.3.1-клиент: 32m.]

Кроме того, вы также должны установить значение-Xmx (максимальный размер кучи) как можно ближе к фактическому пиковому использованию памяти вашего приложения. Я считаю, что поведение по умолчанию JVM по-прежнему удваивает размер кучи каждый раз, когда он расширяет ее до максимума. Если вы начнете с 32-метровой кучи и ваше приложение достигнет пика до 65 метров, то в конечном итоге куча вырастет до 32 метров -> 64 метров -> 128 метров.

Вы также можете попробовать сделать это, чтобы сделать VM менее агрессивным в отношении роста кучи:

-XX:MinHeapFreeRatio=40 минимальный процент свободной кучи после GC, чтобы избежать расширения.

У меня есть процесс java(1.6 u25), работающий на linux (centos 6.3 x64) с JAVA_OPTS= - server -Xms128M -Xmx256M -Xss256K -XX:PermSize=32M -XX:MaxPermSize=32M -XX:MaxDirectMemorySize=128M -XX:+UseAdaptiveSizePolicy -XX:MaxDirectMemorySize=128M -XX:+UseParallelGC -XX:+UseParallelOldGC.

Я использую selenium с веб-драйвером phantom-js на виртуальной машине linux. поскольку кажется, что каждый экземпляр phantom потребляет слишком много памяти, после трех экземпляров виртуальная машина выходит из строя, и я должен перезапустить машину. есть ли способ гарантировать, что виртуальная.

Sun JVM требует много памяти для HotSpot, и она отображается в библиотеках времени выполнения в общей памяти.

Если память является проблемой, рассмотрите возможность использования другого JVM, подходящего для встраивания. IBM имеет j9, и есть открытый исходный код "jamvm", который использует библиотеки GNU classpath. Кроме того, у Sun есть писк JVM, работающий на SunSPOTS, так что есть альтернативы.

Просто мысль, но вы можете проверить влияние опции ulimit -v .

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

Одним из способов уменьшения размера кучи в системе с ограниченными ресурсами может быть игра с переменной -XX:MaxHeapFreeRatio. Обычно это значение равно 70 и является максимальным процентом кучи, которая свободна до того, как GC уменьшит ее. Установите его на более низкое значение,и вы увидите, например, в профилировщике jvisualvm, что для вашей программы обычно используется меньший размер кучи.

EDIT: чтобы установить небольшие значения для -XX:MaxHeapFreeRatio, вы также должны установить -XX:MinHeapFreeRatio Напр.

EDIT2: добавлен пример для реального приложения, которое запускает и выполняет ту же задачу, один с параметрами по умолчанию и один с параметрами 10 и 25 в качестве параметров. Я не заметил никакой реальной разницы в скорости, хотя java теоретически должен использовать больше времени для увеличения кучи в последнем примере.

Default parameters

В конце концов, максимальная куча равна 905, используемая куча-378

MinHeap 10, MaxHeap 25

В конце концов, максимальная куча равна 722, используемая куча-378

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

Sun java 1.4 имеет следующие аргументы для управления размером памяти:

-Xmsn Укажите начальный размер пула выделения памяти в байтах. Это значение должно быть кратно 1024 больше 1 МБ. Добавьте букву К или к, Чтобы обозначить килобайты, или М или М , чтобы обозначить мегабайты. Значение по умолчанию - 2 МБ. Примеры:

-Xmxn Укажите максимальный размер пула выделения памяти в байтах. Это значение должно быть кратно 1024 больше 2 МБ. Добавить букву К или K, чтобы указать килобайты, или m или M , чтобы указать мегабайты. Значение по умолчанию -64 МБ. Примеры:

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

Кроме того, вы можете попробовать какой-нибудь другой JVM, а затем Sun one, с меньшим объемом памяти, но я не могу посоветовать здесь.

Похожие вопросы:

Простая программа: public class SleepTest < public static void main(String[] args) throws InterruptedException < Thread.sleep(60 * 1000); >> Затем $ javac SleepTest.java $ java -cp . SleepTest Для.

Я тестировал объем памяти java на Linux. Когда вы просто смотрите на приложение, которое делает абсолютно NOTHING, оно уже сообщает, что используется 11 MB. При выполнении того же самого на машине.

У меня есть программа Java для запуска на Solaris 10 X86 с 2 ГБ физической памяти и 2 ГБ подкачки. Программа отлично работает в Linux 64-bit, она потребляет всего около 450 МБ памяти. Однако, когда.

Я работаю во встроенной среде, где ресурсы довольно ограничены. Мы пытаемся использовать node.js, который хорошо работает, но обычно потребляет около 60 мегабайт виртуальной памяти (реальная.

Я пытаюсь глубоко понять управление виртуальной памятью в OS Linux. Я действительно не понимаю, как OS определяет размер VM для процесса. Я знаю, что 32-битный x86 OS может дать до 3 GB адресного.

У меня есть процесс java(1.6 u25), работающий на linux (centos 6.3 x64) с JAVA_OPTS= - server -Xms128M -Xmx256M -Xss256K -XX:PermSize=32M -XX:MaxPermSize=32M -XX:MaxDirectMemorySize=128M.

Я использую selenium с веб-драйвером phantom-js на виртуальной машине linux. поскольку кажется, что каждый экземпляр phantom потребляет слишком много памяти, после трех экземпляров виртуальная.

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

Я выполняю задание spark на кластере пряжи с 2 узлами. Мой набор данных невелик (< 100 МБ) только для тестирования, и рабочий убивается, потому что он просит слишком много виртуальной памяти.

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

У меня проблема с приложением Java, работающим под Linux.

Когда я запускаю приложение, используя максимальный размер кучи по умолчанию (64 МБ), я вижу, используя приложение tops, что 240 МБ виртуальной памяти выделяются для приложения. Это создает некоторые проблемы с некоторыми другими программами на компьютере, которые относительно ограничены в ресурсах.

Насколько я понимаю, зарезервированная виртуальная память не будет использоваться в любом случае, потому что, как только мы достигаем предела кучи, создается OutOfMemoryError исключение. Я запустил одно и то же приложение под Windows и вижу, что размер виртуальной памяти и размер кучи одинаковы.

Есть ли способ настроить виртуальную память для процесса Java под Linux?

Редактировать 1 : проблема не в куче. Проблема в том, что если я установлю, например, кучу 128 МБ, Linux все равно выделит 210 МБ виртуальной памяти, которая никогда не нужна **.

Редактировать 2 : Использование ulimit -v позволяет ограничить объем виртуальной памяти. Если размер установлен ниже 204 МБ, приложение не будет работать, даже если ему не нужно 204 МБ, только 64 МБ. Поэтому я хочу понять, почему Java требует так много виртуальной памяти. Можно ли это изменить?

Редактировать 3 : в системе работает несколько других приложений, которые встроены. И система имеет ограничение виртуальной памяти (из комментариев, важные детали).

Почему вы обеспокоены использованием виртуальной памяти? Если вы действительно хотите быть обеспокоенным, посмотрите на использование резидентной памяти и прочитайте следующие команды: free, ps, top. В системе работает несколько других приложений, которые встроены. И система имеет ограничение виртуальной памяти. Какую реализацию Java вы используете. IIRC, бесплатное стандартное (не OpenJDK) решение Sun JRE не лицензировано для встроенного использования. Я думаю, что я не использовал «встроенную» часть . она ограничена в памяти и аппаратное обеспечение настроено, но это все еще стандартный компьютер

Это была давняя жалоба на Java, но она в значительной степени бессмысленна и обычно основана на поиске неверной информации. Обычная формулировка выглядит примерно так: «Hello World на Java занимает 10 мегабайт! Зачем это нужно?» Что ж, вот способ заставить Hello World на 64-битной JVM претендовать на 4 гигабайта . хотя бы одним способом измерения.

В Linux команда top выдает несколько разных чисел для памяти. Вот что говорит пример Hello World:

  • VIRT - это пространство виртуальной памяти: сумма всего на карте виртуальной памяти (см. Ниже). Это в значительной степени бессмысленно, кроме случаев, когда это не так (см. Ниже).
  • RES - это размер резидентного набора: количество страниц, которые в настоящее время находятся в оперативной памяти. Почти во всех случаях это единственное число, которое вы должны использовать, когда говорите «слишком большой». Но это все еще не очень хороший показатель, особенно если говорить о Java.
  • SHR - это объем резидентной памяти, который используется совместно с другими процессами. Для процесса Java это обычно ограничивается общими библиотеками и отображенными в память JAR-файлами. В этом примере у меня был запущен только один процесс Java, поэтому я подозреваю, что 7k - это результат использования библиотек ОС.
  • SWAP не включен по умолчанию и здесь не отображается. Он указывает объем виртуальной памяти, которая в настоящее время находится на диске, независимо от того , находится ли она на самом деле в области подкачки . Операционная система очень хорошо хранит активные страницы в оперативной памяти, и единственные способы ее замены - (1) купить больше памяти или (2) сократить количество процессов, поэтому лучше игнорировать это число.

Ситуация для диспетчера задач Windows немного сложнее. В Windows XP есть столбцы «Использование памяти» и «Размер виртуальной памяти», но в официальной документации ничего не говорится о том, что они означают. Windows Vista и Windows 7 добавляют больше столбцов, и они фактически задокументированы . Из них измерение «Рабочий набор» является наиболее полезным; это примерно соответствует сумме RES и SHR в Linux.

Виртуальная память, используемая процессом, представляет собой сумму всего, что находится в карте памяти процесса. Это включает в себя данные (например, кучу Java), а также все общие библиотеки и файлы отображения памяти, используемые программой. В Linux вы можете использовать команду pmap, чтобы увидеть все объекты, отображенные в пространстве процесса (с этого момента я буду ссылаться только на Linux, потому что это то, что я использую; я уверен, что есть эквивалентные инструменты для Windows). Вот выдержка из карты памяти программы «Hello World»; вся карта памяти имеет длину более 100 строк, и нет ничего необычного в том, чтобы иметь список из тысячи строк.

Краткое объяснение формата: каждая строка начинается с адреса виртуальной памяти сегмента. Далее следуют размер сегмента, разрешения и источник сегмента. Этот последний элемент является либо файлом, либо «anon», который указывает блок памяти, выделенный через mmap .

Начиная сверху, мы имеем

  • Загрузчик JVM (т.е. программа, которая запускается при вводе java ). Это очень мало; все, что он делает, это загружает в разделяемые библиотеки, где хранится настоящий код JVM.
  • Связка аноновых блоков, содержащих кучу Java и внутренние данные. Это Sun JVM, поэтому куча разбита на несколько поколений, каждое из которых является собственным блоком памяти. Обратите внимание, что JVM выделяет пространство виртуальной памяти на основе -Xmx значения; это позволяет ему иметь непрерывную кучу. Это -Xms значение используется внутри, чтобы сказать, сколько кучи «используется» при запуске программы, и запустить сборку мусора при приближении к этому пределу.
  • Отображаемый в память JAR-файл, в данном случае файл, содержащий «классы JDK». Когда вы отображаете JAR в память, вы можете очень эффективно обращаться к файлам в нем (вместо того, чтобы каждый раз читать его с самого начала). Sun JVM отобразит в памяти все файлы JAR на пути к классам; если вашему приложению необходим код для доступа к JAR, вы также можете отобразить его в памяти.
  • Данные по потокам для двух потоков. Блок 1M - это стек потоков. У меня не было хорошего объяснения для блока 4k, но @ericsoe идентифицировал его как «защитный блок»: у него нет разрешений на чтение / запись, поэтому при обращении к нему будет возникать ошибка сегмента, и JVM отлавливает это и переводит это к StackOverFlowError . Для реального приложения вы увидите десятки, если не сотни этих записей, повторенных через карту памяти.
  • Одна из разделяемых библиотек, которая содержит реальный код JVM. Есть несколько из них.
  • Общая библиотека для стандартной библиотеки C. Это только одна из многих вещей, которые загружает JVM, которые не являются строго частью Java.

Совместно используемые библиотеки особенно интересны: каждая разделяемая библиотека имеет как минимум два сегмента: сегмент только для чтения, содержащий код библиотеки, и сегмент чтения-записи, содержащий глобальные данные о процессах для библиотеки (я не знаю, что сегмент без разрешений есть; я видел его только на x64 Linux). Часть библиотеки, доступная только для чтения, может использоваться всеми процессами, которые используют библиотеку; например, libc имеет 1,5 МБ виртуальной памяти, которую можно использовать совместно.

Карта виртуальной памяти содержит много вещей. Некоторые из них доступны только для чтения, некоторые из них являются общими, а некоторые выделяются, но никогда не затрагиваются (например, почти все 4 Гб кучи в этом примере). Но операционная система достаточно умна, чтобы загружать только то, что ей нужно, поэтому размер виртуальной памяти в значительной степени не имеет значения.

Размер виртуальной памяти важен, если вы работаете в 32-битной операционной системе, где вы можете выделить только 2 ГБ (или, в некоторых случаях, 3 ГБ) адресного пространства процесса. В этом случае вы имеете дело с дефицитным ресурсом, и вам, возможно, придется пойти на компромисс, например, уменьшить размер кучи, чтобы отобразить в памяти большой файл или создать много потоков.

Но, учитывая, что 64-битные машины распространены повсеместно, я не думаю, что пройдет много времени, прежде чем объем виртуальной памяти станет абсолютно неактуальной статистикой.

Размер резидентного набора - это та часть виртуальной памяти, которая фактически находится в ОЗУ. Если ваш RSS становится значительной частью вашей общей физической памяти, возможно, пришло время начать беспокоиться. Если ваш RSS-канал начинает занимать всю вашу физическую память, а ваша система начинает обмениваться, уже давно пора начать беспокоиться.

Но RSS также вводит в заблуждение, особенно на слегка загруженной машине. Операционная система не тратит много сил на восстановление страниц, используемых процессом. Это дает мало пользы и может привести к дорогостоящему отказу страницы, если процесс коснется страницы в будущем. В результате статистика RSS может включать в себя множество страниц, которые не используются активно.

Если вы не поменялись местами, не слишком переживайте о том, что говорит вам различная статистика памяти. С оговоркой, что постоянно растущая RSS может указывать на какую-то утечку памяти.

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

Доступ к диску (т. Е. К базе данных) стоит дорого, а память - дешево. Если вы можете обменять одно на другое, сделайте это.

Описание выделения памяти JVM по умолчанию

JAVA_OPTS="-server -Xms2048m -Xmx2048m -XX:PermSize=128M -XX:MaxPermSize=128m"

Распределение памяти кучи JVM

-Xms Принято считать, что при запуске JVM изначально выделяется физическая память, а по умолчанию используется 1/64 физической памяти;
-Xmx Максимальная физическая память, выделяемая при работе JVM, согласована, и по умолчанию она составляет 1/4 физической памяти;

Когда JVM работает, когда объем свободной памяти кучи JVM превышает 70% ее собственной памяти, JVM автоматически освобождает память, пока не достигнет -Xms Согласованное минимальное значение, которое обычно возникает после GC, когда JVM настраивает свою собственную память кучи.

Оптимизация памяти
, поэтому мы можем установить его вручную -Xms против -Xmx Равно избегать корректировки размера кучи после каждого GC.
-рекомендованная максимальная настройка памяти кучи -Xmx 80% от максимально доступной памяти.

Переполнение памяти
- -Xms < -Xmx , JVM не запускается;
- -Xmx > Когда физическая память доступна, JVM не запускается;
- Объем памяти, используемой приложением при запуске и запуске, превышает -Xmx Когда, переполнение памяти JVM (OutOfMemoryError: пространство кучи Java);

Распределение памяти без кучи JVM

-XX:PermSize Установите начальное значение памяти без кучи, по умолчанию 1/64 физической памяти;
-XX:MaxPermSize Установите максимальный объем памяти без кучи, по умолчанию это 1/4 физической памяти;

Память без кучи JVM (область постоянной памяти), используемая для хранения информации о классах и мета-версиях, все классы приложения помещаются в эту область при загрузке JVM. Это и экземпляр класса хранения ( Instance ) Куча области ( Heap ) Разное, GC GC ( Garbage Collection ) Не влияет на область памяти без кучи во время выполнения основной программы ( PermGen space ) Очистить.

Оптимизация памяти
-Рекомендуется выделить в соответствии с реальной ситуацией приложения развертывания сервера, вы можете передать jconsole Инструмент наблюдает за использованием памяти после запуска JVM и выделяет ее;
- рекомендуется -XX:PermSize против -XX:MaxPermSize Значение установлено равным.

Переполнение памяти
- Когда JVM начинает загружать приложение, объем памяти, используемой для загрузки класса, превышает -XX:MaxPermSize , Ошибка переполнения памяти без кучи (OutOfMemoryError: пространство PermGen);
- когда -Xmx + -XX:MaxPermSize Когда память, установленная этими двумя, превышает доступную физическую память системы, JVM не запускается;

Ненормальная ошибка в памяти JVM

OutOfMemoryError: Java heap space

OutOfMemoryError: PermGen space

OutOfMemoryError: unable to create new native thread

Это явление относительно редкое и странное, в основном связанное с соотношением jvm и системной памяти. Эта странная вещь связана с тем, что JVM была выделена системой большой объем памяти (например, 1,5 ГБ), и она должна занимать как минимум половину доступной памяти.

Просмотр информации о памяти JVM

использование jconsole Инструменты для просмотра оперативной памяти JVM

в window Установка системы JDK Приходит в сумке jconsole Инструменты могут быть переданы jconsole Инструменты для связи с удаленными серверами JVM Примеры, просмотр JVM Память во время выполнения.
Кстати, представьте еще один инструмент, который поставляется с JDK jvisualvm Вы можете использовать этот инструмент для выполнения тестов производительности программ JAVA, анализа данных о производительности программ и т. Д. (Вы можете использовать Baidu для конкретного использования).
Кстати, представьте еще один инструмент, который поставляется с JDK jmc Вы можете использовать этот инструмент для удаленного мониторинга JVM. После запуска этого инструмента основной интерфейс представит инструмент «Что такое Oracle Java Mission Control?».

позиция: %JAVA_HOME%/bin/jconsole.exe
Расположение: %JAVA_HOME%/bin/jvisualvm.exe
Расположение: %JAVA_HOME%/bin/jmc.exe

Используйте программу JAVA для просмотра оперативной памяти JVM

Настройте Tomcat для запуска с catalina.sh и настройте память JVM

Таким образом, было уделено внимание некоторым аспектам памяти JVM. Ниже приведено прямое описание того, как Tomcat начинает настраивать выделение памяти JVM через catalina.sh.

войти %TOMCAT_HOME%/bin Под каталогом найдите catalina.sh скрипт.
1. Проверьте это catalina.sh Работает ли служба нормально.
Выполните следующую команду, вы увидите некоторую информацию о запуске Tomcat.

2. Используйте vim Редактор открывается catalina.sh скрипт. Добавьте следующий код, прежде чем скрипт выполнит оператор.



Затем повторно запустите сценарий, чтобы запустить службу Tomcat.

Замечания: в исполнении ./catalina.sh stop После этого журнал предлагает нам следующие два предложения, основное значение в Tomcat 8.0 Начало версии, не нужно устанавливать -PermSize 、 -MaxPermSize Эти два параметра. Так что просто удалите его в конфигурации.
OpenJDK 64-Bit Server VM warning: ignoring option PermSize=128M; support was removed in 8.0
OpenJDK 64-Bit Server VM warning: ignoring option MaxPermSize=128m; support was removed in 8.0

Настройте Tomcat для запуска daemon.sh в фоновом режиме и настройте память JVM

Таким образом, было уделено внимание некоторым аспектам памяти JVM. Ниже приведено прямое описание того, как Tomcat начинает настраивать выделение памяти JVM через catalina.sh.

войти %TOMCAT_HOME%/bin Под каталогом найдите daemon.sh скрипт.
1. Проверьте это daemon.sh Работает ли служба нормально.
Выполните следующую команду, вы увидите некоторую информацию о запуске Tomcat.

Примечания: Мы не видели из процесса информации -server -Xms896m -Xmx896m Информация о распределении памяти, то есть Tomcat daemon.sh Скрипт запуска не наследуется catalina.sh Информация о конфигурации в скрипте, поэтому вам нужно вручную daemon.sh Настройте параметры выделения памяти JVM.

2. Используйте vim Редактор открывается daemon.sh скрипт. Добавьте следующий код, прежде чем скрипт выполнит оператор.
JAVA_OPTS="-server -Xms896m -Xmx896m"


Поиск под vim JAVA_OPTS= Как показано ниже, настройте параметры выделения памяти JVM сзади.

Затем сохраните и выйдите.
Остановите службу и перезапустите службу.

у меня проблема с Java-приложением, работающим под Linux.

когда я запускаю приложение, используя максимальный размер кучи по умолчанию (64 МБ), я вижу, используя приложение tops, что 240 МБ виртуальной памяти выделены приложению. Это создает некоторые проблемы с некоторым другим программным обеспечением на компьютере, который относительно ограничен ресурсами.

зарезервированная виртуальная память все равно не будет использоваться, насколько я понимаю, потому что как только мы достигнем кучи ограничить OutOfMemoryError бросается. Я запустил то же приложение под windows, и я вижу, что размер виртуальной памяти и размер кучи похожи.

есть ли в любом случае, что я могу настроить виртуальную память, используемую для процесса Java под Linux?

изменить 1: проблема не в куче. Проблема в том, что если я установил кучу 128 МБ, например, все еще Linux выделяет 210 МБ виртуальной памяти, которая не нужна никогда.**

изменить 2: используя ulimit -v позволяет ограничить объем виртуальной памяти. Если размер установлен ниже 204 МБ, то приложение не будет работать, даже если ему не нужно 204 МБ, только 64 МБ. Поэтому я хочу понять, почему Java требует так много виртуальной памяти. Можно ли это изменить?

Edit 3: есть несколько других приложений, работающих в системе, которая встроена. И у системы есть ограничение виртуальной памяти (из комментариев, важная деталь).

это была давняя жалоба с Java, но она в значительной степени бессмысленна и обычно основана на взгляде на неправильную информацию. Обычная фразировка-это что-то вроде "Hello World на Java занимает 10 мегабайт! Зачем ему это нужно?"Ну, вот способ сделать Hello World на 64-битной претензии JVM, чтобы занять 4 гигабайта . по крайней мере, по одной форме измерения.

  • VIRT-это пространство виртуальной памяти: сумма всего на карте виртуальной памяти (см. ниже). Это в значительной степени бессмысленно, за исключением случаев, когда это не так (см. ниже).
  • RES-размер резидентного набора: количество страниц, которые в настоящее время находятся в ОЗУ. Почти во всех случаях это единственное число, которое вы должны использовать, говоря "слишком большой."Но это все еще не очень хорошее число, особенно когда речь идет о Java.
  • SHR-это объем резидентной памяти, которая используется совместно с другими процессами. Для процесса Java это обычно ограничивается общими библиотеками и сопоставленными с памятью JARfiles. В этом примере у меня был только один процесс Java, поэтому я подозреваю, что 7k является результатом библиотек, используемых ОС.
  • SWAP по умолчанию не включен и не отображается здесь. Он указывает объем виртуальной памяти, который в настоящее время резидент на диске,является ли это на самом деле в пространстве подкачки. ОС очень хорошо поддерживает активные страницы в ОЗУ, и единственными средствами для замены являются (1) покупка больше памяти или (2) уменьшение количества процессов, поэтому лучше игнорировать это число.

ситуация для диспетчера задач Windows немного сложнее. В Windows XP есть столбцы" использование памяти "и" размер виртуальной памяти", но официальный документация молчит о том, что они означают. Windows Vista и Windows 7 добавляют больше столбцов, и они на самом деле документирована. Из них измерение "рабочего набора" является наиболее полезным; оно примерно соответствует сумме RES и SHR в Linux.

виртуальная память, потребляемая процессом, - это общая сумма всего, что находится на карте памяти процесса. Это включает в себя данные (например, кучу Java), но и все динамические библиотеки и отображенные в память файлы используются в программе. В Linux вы можете использовать pmap команда, чтобы увидеть все вещи, отображенные в пространство процесса (отсюда я буду ссылаться только на Linux, потому что это то, что я использую; я уверен, что есть эквивалентные инструменты для Windows). Вот отрывок из карты памяти программы "Hello World"; вся карта памяти имеет длину более 100 строк, и нет ничего необычного в том, чтобы иметь список из тысячи строк.

A краткое объяснение формата: каждая строка начинается с адреса виртуальной памяти сегмента. За этим следует размер сегмента, разрешения и источник сегмента. Этот последний элемент является либо файлом, либо "anon", что указывает на блок памяти, выделенный через вызов mmap.

начиная с самого верха, у нас есть

  • загрузчик JVM (т. е. программа, которая запускается при вводе java ). Это очень мало; все, что он делает, это загрузка в общий библиотеки, где хранится реальный код JVM.
  • куча блоков anon, содержащих кучу Java и внутренние данные. Это Sun JVM, поэтому куча разбивается на несколько поколений, каждое из которых является собственным блоком памяти. Обратите внимание, что JVM выделяет пространство виртуальной памяти на основе -Xmx значение; это позволяет ему иметь непрерывную кучу. The -Xms value используется внутренне, чтобы сказать, сколько кучи "используется" при запуске программы и запускать сборку мусора как это предела.
  • сопоставленный с памятью JARfile, в этом случае файл, содержащий " классы JDK."Когда вы составляете карту памяти банки, вы можете получить доступ к файлам внутри нее очень эффективно (по сравнению с чтением с самого начала каждый раз). Sun JVM будет сопоставлять все банки на пути к классам; если вашему коду приложения нужно получить доступ к банку, вы также можете сопоставить его с памятью.
  • данные по каждому потоку для двух потоков. Блок 1M-это стек потоков; я не знаю, что входит в блок 4K. Для реального приложения вы увидите десятки, если не сотни этих записей, повторяющихся через карту памяти.
  • одна из общих библиотек, которая содержит фактический код JVM. Их несколько.
  • общая библиотека для стандартной библиотеки языка Си. Это всего лишь одна из многих вещей, которые загружает JVM, которые не являются строго частью Java.

общие библиотеки особенно интересны: каждая общая библиотека имеет по крайней мере два сегмента: только для чтения сегмент, содержащий код библиотеки, и сегмент чтения и записи, содержащий глобальные данные для каждого процесса для библиотеки (я не знаю, что такое сегмент без разрешений; я видел его только на x64 Linux). Часть библиотеки, доступная только для чтения, может совместно использоваться всеми процессами, использующими библиотеку; например, libc имеет 1,5 м пространства виртуальной памяти, которое может быть общим.

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

где важен размер виртуальной памяти, это если вы работаете в 32-разрядной операционной системе, где вы можете выделить только 2 ГБ (или, в некоторых случаях, 3 ГБ) адресного пространства процесса. В таком случае вы имеете дело с редким и, возможно, придется пойти на компромисс, например, уменьшить размер кучи, чтобы отобразить в памяти большой файл или создать много потоков.

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

размер резидентного набора - это та часть пространства виртуальной памяти, которая фактически находится в ОЗУ. Если ваш RSS растет, чтобы быть значительным часть вашей общей физической памяти, это может быть время, чтобы начать беспокоиться. Если RSS занимает всю вашу физическую память, а система начинает меняться местами, давно пора начать беспокоиться.

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

если вы не меняетесь местами, не слишком беспокоиться о том, что различные статистики памяти говорят вам. С оговоркой, что постоянно растущий RSS может указывать на какую-то утечку памяти.

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

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

существует известная проблема с Java и glibc >= 2.10 (включая Ubuntu >= 10.04, RHEL >= 6).

лекарство это ОКР. переменная: export MALLOC_ARENA_MAX=4 Если вы используете Tomcat, вы можете добавить это .

резидентной памяти был известен ползучести аналогично утечка памяти или фрагментация памяти.

поиск MALLOC_ARENA_MAX на Гугле или более ссылок.

вы можете настроить и другие параметры malloc для оптимизации низкой фрагментации выделенной памяти:

объем памяти, выделенный для процесса Java, в значительной степени соответствует тому, что я ожидал бы. У меня были аналогичные проблемы с запуском Java на встроенных/ограниченных системах памяти. Бег!--1 - >любой приложение с произвольными ограничениями VM или на системах, которые не имеют достаточного количества свопа, как правило, ломаются. Похоже, это характер многих современных приложений, которые не предназначены для использования в системах с ограниченными ресурсами.

У вас есть несколько вариантов вы можете попробовать и ограничить След памяти JVM. Это может уменьшить объем виртуальной памяти:

- XX: ReservedCodeCacheSize=32M размер кэша зарезервированного кода (в байтах) - максимум размер кэша кода. [Solaris 64-разрядная версия, amd64, и-сервер x86: 48m; в 1.5.0_06 и более ранних версий, Solaris 64-бит и and64: 1024m.]

- XX: MaxPermSize=64m размер постоянного поколения. [5.0 и новее: 64-битные VMs масштабируются на 30% больше; 1.4 для amd64: 96М; 1.3.1 -клиент: 32m.]

кроме того, вы также должны установить-Xmx (максимальный размер кучи) как можно ближе к фактическое пиковое использование памяти приложения. Я считаю, что поведение по умолчанию JVM по-прежнему двойной размер кучи каждый раз, когда он расширяет его до максимального. Если вы начнете с кучи 32M и ваше приложение достигнет пика 65M, то куча будет расти 32M - > 64M- > 128M.

вы также можете попробовать это сделать ВМ менее агрессивно о росте кучи:

- XX: MinHeapFreeRatio=40 минимальный процент кучи свободной после GC к избегайте расширения.

кроме того, из того, что я помню из экспериментов с этим несколько лет назад, количество загруженных собственных библиотек оказало огромное влияние на минимальный след. Загрузка java.сеть.Сокет добавил более 15M, если я правильно помню (и я, вероятно, не).

Sun JVM требует много памяти для HotSpot, и она сопоставляется в библиотеках времени выполнения в общей памяти.

Если проблема с памятью, рассмотрите возможность использования другой JVM, подходящей для встраивания. IBM имеет j9, и есть открытый исходный код "jamvm", который использует библиотеки GNU classpath. Также У Sun есть писк JVM, работающий на солнечных пятнах, поэтому есть альтернативы.

просто мысль, но вы можете проверить влияние a ulimit -v опции.

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

одним из способов уменьшения кучи системы с ограниченными ресурсами может быть игра с переменной-XX: MaxHeapFreeRatio. Это обычно устанавливается в 70 и является максимальным процентом кучи, которая свободна до того, как GC сжимает ее. Установив его на более низкое значение, вы увидите, например, в профилировщике jvisualvm, что для вашей программы обычно используется меньшая куча.

EDIT: чтобы установить небольшие значения для-XX: MaxHeapFreeRatio, вы также должны установить-XX:MinHeapFreeRatio Например

EDIT2: добавлен пример для реального приложения, которое запускается и выполняет ту же задачу, один с параметрами по умолчанию и один с 10 и 25 в качестве параметров. Я не заметил никакой реальной разницы в скорости, хотя Java теоретически должна использовать больше времени для увеличения кучи в последнем примере.

Default parameters

в конце, максимальная куча 905, используемая куча 378

MinHeap 10, MaxHeap 25

в конце, максимальная куча 722, используемая куча 378

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

java 1.4 Sun имеет следующие аргументы для управления размером памяти:

-Xmsn Укажите начальный размер пула распределения памяти в байтах. Это значение должно быть кратно 1024 больше чем 1МБ. Добавить букву k или K, чтобы указать килобайты, или m или M для обозначения мегабайт. Неисполнение значения 2Мб. Примеры:

- Xmxn Укажите максимальный размер пула распределения памяти в байтах. Это значение должно быть кратно 1024 больше чем 2Мб. Добавить букву k или K, чтобы указать килобайты, или m или M для обозначения мегабайт. Неисполнение значение 64Мб. Примеры:

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

Alernatively, вы можете попробовать другую JVM, а затем Sun one, с меньшим объемом памяти, но я не могу посоветовать здесь.

Читайте также: