У меня есть машина с 16G RAM. Я запускаю Java-приложение с аргументами -Xms9G -Xmx9G. Когда я запускаю команду top, я вижу, что мой Java-процесс принимает 13,8 г VIRT , но только 4,6 г RES .

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 5019 root      20   0 13.8g 4.7g  18m S  0.7 30.7   3:28.39 java                                     

При выполнении команды pmap я вижу, что в RES присутствует только ~ 3,9 г кучи, остальные 5,7 г в виртуальном . ,

Address           Kbytes     RSS   Dirty Mode   Mapping
0000000580000000 9452384 4074228 4074228 rw---    [ anon ]

Наблюдая за HPCUR с помощью jvmtop, я наблюдаю, что GC срабатывает, когда HPCUR достигает около 3 г .

PID MAIN-CLASS        HPCUR HPMAX NHCUR NHMAX    CPU     GC    VM USERNAME   #T DL
 5019 .1-SNAPSHOT.jar  408m 9216m  192m   n/a  0.25%  0.00% O8U20   webapp  823

Я заметил, что RES для процесса увеличивается постепенно , объем памяти кучи в RES (по pmap) также постепенно увеличивается. В результате порог ГХ увеличивается.

У меня есть несколько вопросов об этом поведении.

  1. Используется только куча, которая присутствует в RES, а не VIRT?
  2. Если я выделил кучу мин 9G (-Xms), то сначала почему выделено только 3,9 г RES. Разве это не то же самое, что поддерживать -Xms на низком уровне? Какой смысл хранить -Xms = -Xmx тогда?
  3. На основании чего решено, сколько кучи должно быть в RES? Где-то читал, что это управляется ОС, но какая-то грубая логика?
  4. Есть ли способ убедиться, что выделенная куча действительно используется?
2
FlapPy 28 Май 2019 в 07:01

2 ответа

Лучший ответ
  1. Да HEAP - это RES (если он вписывается в основной объем памяти)
  2. Этот ответ предполагает, что -Xms является подсказкой для GC, в какой момент необходима полная сборка мусора. Тестируя с моей локальной JVM, я могу подтвердить, что он не сразу резервирует память. Что вы получаете, так это то, что ваша JVM не блокирует много неиспользуемой памяти, но быстрее достигнет нижней границы, поскольку будет меньше запусков GC.
  3. Ответил 1.: RES всегда содержит все HEAP
  4. Насколько я понимаю, ваши варианты достигнут того, что вы собираетесь. Ваше приложение будет захватывать 9 ГБ памяти и затем чаще запускать сборку мусора. Есть другие варианты, такие как { {X0}} и параметры, которые зависят от используемого сборщика мусора Если вам нужно больше оптимизации.

Вы печатали журналы GC и проверяли, что что-то не так? Если вы увидите, что GC запускается до запуска 9G, я бы посмотрел дальше. Если до попадания в 9G GC практически не запускается, я бы сказал, что все в порядке.

-1
cmoetzing 4 Июн 2019 в 08:55
  • VIRT обозначает Виртуальную память - это все зарезервированное адресное пространство процесса. RSS - размер резидентного набора - часть виртуального адресного пространства, выделенная в физической памяти. Для любого диапазона адресов (не только кучи) RSS является подмножеством VIRT, возможно, полным или пустым. Похоже, вы уже исследовали pmap - для каждого виртуального диапазона адресов он показывает точный объем физически выделенной памяти (RSS).
  • ОС лениво распределяет физические страницы при первом доступе. Вот почему даже выделенная память не является частью RSS, пока соответствующие страницы не будут прочитаны или записаны. Тот факт, что большая часть кучи отсутствует в RSS, означает, что эта часть кучи никогда не затрагивалась. См. Также этот вопрос.
  • Существует опция JVM -XX:+AlwaysPreTouch, которая принудительно затрагивает каждую страницу кучи, делая ее частью RSS. Попробуйте java -Xms9G -Xmx9G -XX:+AlwaysPreTouch.
3
apangin 29 Май 2019 в 07:58