Простому Hello World требуется 10 ГБ виртуальной памяти на 64-разрядной машине против 1 ГБ на 32-разрядной?

Запустив простую Java-программу на нашей рабочей машине, я заметил, что эта программа съедает больше 10G virt. Я знаю, что виртуальная память не так актуальна, но, по крайней мере, я хотел бы понять, зачем это нужно.

public class Main {
  public static void main(String[] args) {
        System.out.println("Hello World!");
        try {
                Thread.sleep(10000);
        } catch(InterruptedException e) {
                /* ignored */
        }
  }
}

Вот что говорит top, когда я запускаю эту маленькую программу:

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
18764 myuser    20   0 10.2g  20m 8128 S  1.7  0.1   0:00.05 java

Кто-нибудь знает, почему это происходит?

uname -a говорит:

Linux m4fxhpsrm1dg 2.6.32-358.18.1.el6.x86_64 #1 SMP Fri Aug 2 17:04:38 EDT 2013 x86_64 x86_64 x86_64 GNU/Linux

На более старой 32-битной Linux-машине та же программа потребляет всего около 1G virt. Оперативная память на старой машине 4Гб, на новой 32Гб.


person user3246431    schedule 29.04.2014    source источник
comment
@jwenting это 1 ГБ ВИРТУАЛЬНОЙ памяти, а не обязательно физической памяти.   -  person CurtisHx    schedule 29.04.2014
comment
Сколько памяти у вашей машины? Насколько старший? Как указывали другие, именно JavaVM занимает фиксированный объем памяти.   -  person Marcus Bitzl    schedule 29.04.2014
comment
Рассматриваю похожую проблему. Вы случайно не на Red Hat Enterprise 6? Попробуйте установить MALLOC_ARENA_MAX=4 в качестве переменной среды и перезапустите тест. Дополнительная информация: ibm.com/developerworks/community/blogs /кевгриг/вход/   -  person Brian    schedule 29.04.2014
comment
@CurtisHx: Подумай об этом. Один гигабайт виртуальной памяти! Это все еще безумие, что вы делаете с таким большим адресным пространством?   -  person MSalters    schedule 29.04.2014
comment
@MSalters Предварительное выделение (без фиксации) пространства для управляемой кучи. Это 64-битный мир, вы можете иметь столько виртуального пространства, сколько захотите, это буквально не имеет значения.   -  person Cat Plus Plus    schedule 29.04.2014
comment
@CatPlusPlus: вам нужно несколько байтов состояния на страницу (где эта страница находится физически, в ОЗУ, на диске или отсутствует?). Ваш Hello, World буквально использует мегабайты таблиц страниц, ни одна из которых не нужна.   -  person MSalters    schedule 29.04.2014
comment
@MSalters это JVM, а не код Hello World, который предварительно выделяет все это адресное пространство.   -  person NWard    schedule 29.04.2014
comment
Я думаю, что это может быть первый вопрос, который я когда-либо видел, и который, вероятно, более уместен на StackOverflow, чем там, где он был опубликован ... лол.   -  person jpmc26    schedule 30.04.2014
comment
@NWard: Итак? JVM выделяет это место для запуска HelloWorld. Я не пытаюсь обвинить автора HelloWorld, это явный сбой JVM. (Использование экспоненциального роста управляемой кучи поддерживает амортизацию стоимости выделения на уровне O(1), даже если вы начнете с 1 КБ вместо 1 ГБ)   -  person MSalters    schedule 30.04.2014
comment
@MSalters: он распределяется в процентах от ОЗУ. Если у вас достаточно оперативной памяти, чтобы оправдать 10 ГБ виртуального адресного пространства, то буквально мегабайты таблиц страниц — это капля в море. Если у вас так мало ОЗУ, что несколько мегабайт вообще имеют значение, вы будете использовать меньше виртуальной памяти и, следовательно, потребуется меньше для таблиц страниц. Возможно, это не идеально, но это не имеет существенного значения.   -  person Phoshi    schedule 30.04.2014
comment
@MSalters: он использует не так много памяти. Он только резервирует его - очень большая разница.   -  person a_horse_with_no_name    schedule 30.04.2014
comment
@a_horse_with_no_name: Я хочу сказать, что сами резервирования составляют несколько мегабайт. Это проблема для программирования в стиле UNIX, когда у вас могут быть тысячи небольших процессов, работающих бок о бок. Это не проблема, если весь процесс занимает всего лишь мегабайт.   -  person MSalters    schedule 30.04.2014
comment
Стах! Для java много накладных расходов, и есть настраиваемое минимальное использование памяти. Ява не ассемблер.   -  person DwB    schedule 30.04.2014
comment
@MSalters - это не проблема, потому что память фактически не выделена. Все, что выделено, — это адресное пространство, которое является личным для отдельного процесса и (почти) не влияет на другие процессы. Никакая память не будет выделена для адресного пространства, если что-то действительно не использует ее.   -  person Jules    schedule 01.05.2014
comment
@Jules: я знаю, что 1 ГБ на самом деле не выделен. Но будет примерно 4 МБ метаданных, указывающих, какие части из 1 ГБ просто зарезервированы, в ОЗУ и/или на диске. (Предполагается, что один 8-байтовый указатель плюс статус на страницу размером 4 КБ)   -  person MSalters    schedule 01.05.2014
comment
Это не верное предположение. На странице нет элемента данных. Все, что есть, — это запись в простой структуре данных (согласно статье people.csail.mit.edu/nickolai/papers/clements-bonsai.pdf это красно-черное дерево), которое отмечает оговорку и ее длину. Это, вероятно, занимает где-то в районе 32-64 байта, и это тот же объем памяти, независимо от того, насколько велико резервирование.   -  person Jules    schedule 01.05.2014
comment
@MSalters Вы знаете, именно по этой причине языки высокого уровня желательны. Очень немногие люди достаточно хорошо разбираются в базовом программном и аппаратном обеспечении, чтобы избежать большего количества проблем, чем те, которые возникают из-за небольшого недопонимания. Не говоря уже о том, что это означает, что инфраструктура более высокого уровня (JVM, CLR) может приспосабливаться к новым ситуациям — точно так же, как переключатель 32-бит против 64-бит. На конференции Build в этом году на современном C++ был отличный пример, показывающий, что двоичный поиск медленнее, чем линейный поиск (для больших массивов мелких элементов). Предположения больше не работают, система слишком сложна.   -  person Luaan    schedule 07.05.2014
comment
@Luaan Есть несколько хорошо известных случаев, когда бинарный поиск медленнее, чем линейный поиск (например, небольшие массивы (отсортированные или несортированные); большие несортированные массивы, которые будут искаться только один раз и т. д.). Вы имеете в виду, что есть исследования, доказывающие, что линейный поиск лучше, чем бинарный поиск в целом? Если да, то есть ли у вас ссылка на источник, где я мог бы прочитать больше?   -  person Dan Bechard    schedule 07.07.2016
comment
@ Дэн Нет, совсем нет. Если бы это было так, я бы не стал приводить примеры. Как уже упоминалось, доклад Modern C++ о сборке 2014 затрагивает некоторые примеры этого (channel9. msdn.com/Events/Build/2014/2-661). И в своем собственном комментарии вы упоминаете большие несортированные массивы, которые будут искаться только один раз, что потребует двоичного поиска для сортировки массива перед выполнением поиска - линейный поиск будет быстрее. Но даже в отсортированных массивах есть вещи, которые необходимо учитывать, например, проверка границ массива, необходимая для бинарного поиска, но не линейного, прогнозирования ветвлений и т. д.   -  person Luaan    schedule 07.07.2016
comment
@Dan Конечно, имейте в виду, что это всего лишь комментарий, и место ограничено. Там достаточно материала для множества постов в блоге или даже для книги. Но в то время как современные компьютеры притворяются простыми, они ими не являются (я говорю «сегодняшние», но так было примерно с 486 года, и с каждым годом их становится все больше). Вам нужно позаботиться о расположении памяти, использовании кеша, прогнозировании ветвлений, переупорядочивании инструкций и т. д., даже на аппаратном уровне. Затем на уровне программного обеспечения вы получаете множество других вещей, о которых нужно заботиться, например. проверка границ массива, о которой я упоминал.   -  person Luaan    schedule 07.07.2016


Ответы (7)


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

Вы можете выбрать оба с помощью параметров командной строки -Xms и -Xmx. .

person Michael Borgwardt    schedule 29.04.2014
comment
Ждать. ›максимальный размер кучи: Меньше 1/4 физической памяти или 1 ГБ, поэтому максимальный размер кучи по умолчанию ограничен 1 ГБ. Предполагая, что это не изменилось, вы говорите, что начальное распределение выше, чем максимум? Потому что это звучит довольно сломано. - person Bob; 29.04.2014
comment
@Bob Кажется, это относится только к 32-разрядной версии Java и 64-разрядной версии до версии 1.6 на клиентской виртуальной машине. Java 1.6+ 64-бит на серверной ВМ резервирует гораздо больше. - person Luaan; 29.04.2014
comment
@Bob: Примечание. Границы и дроби, указанные для размера кучи, верны для Java SE 5.0. Они, вероятно, будут другими в последующих выпусках, поскольку компьютеры становятся более мощными. - person Michael Borgwardt; 30.04.2014

Виртуальная память действительно не имеет значения для вас.

Основное различие между 32-битной и 64-битной версиями заключается в том, что адресное пространство в 64-битной системе невероятно велико. Если 10 ГиБ кажутся вам много, обратите внимание, что .NET на 64-разрядной версии может использовать такие ТиБы памяти. Тем не менее, в 32-разрядной среде .NET гораздо более консервативен (как и JVM) — адресное пространство составляет всего 4 ГБ — это немного.

Но это не имеет значения - это не имеет значения. Это просто вещь, которая значительно упрощает программирование и не оказывает никакого негативного влияния на основную ОС. Он создает непрерывное адресное пространство для использования виртуальной машиной, а это означает, что вам не нужно фрагментировать кучу (или, что еще хуже, стек, где это более или менее невозможно, но это, как правило, только МиБ или около того) как вам потребуется больше «настоящей» памяти. Когда вы, наконец, выделяете виртуальную память, она становится немного более реальной — в этот момент она более или менее должна поддерживаться некоторым хранилищем данных — будь то файл подкачки (подкачки) или физическая оперативная память.

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

Итак, у вас есть это - виртуальная память почти свободна на 64-битной версии. Основной подход — «если он есть, используйте его». Вы не ограничиваете другие приложения, и это сэкономит вам немало работы, если вы делаете на самом деле в конечном итоге используете его. Но пока этот момент не наступил, у вас есть только оговорка. Это вообще не переводится ни в какую физическую память. Вы не платите за друзей, которые могут прийти сегодня вечером и сесть за ваш стол, но у вас все еще есть место для них, если они придут, и только когда они наконец придут, вы действительно получите «заряд».

См. этот вопрос для получения дополнительной информации о том, как Java ведет себя на разных машинах и в разных версиях: Каков максимальный размер кучи по умолчанию для JVM Sun из Java SE 6? Максимальный размер кучи также определяет объем зарезервированной виртуальной памяти, поскольку куча должно быть непрерывное адресное пространство. Если бы он не был предварительно зарезервирован, могло бы случиться так, что куча не смогла бы расшириться до этого максимального значения, потому что кто-то еще зарезервировал область адресного пространства в том месте, где куча должна расширяться.

person Luaan    schedule 29.04.2014
comment
@gnat Как так? It creates a contiguous address space for the VM to use, which means that you don't have to fragment the heap кажется мне довольно ясной причиной, среди прочего. И я объяснил разницу между 32-битной и 64-битной средой. - person Luaan; 29.04.2014
comment
@gnat Да, объясняя, что предпосылка вопроса (что 10 ГБ виртуального адресного пространства - это как-то плохо или нежелательно) ложна и что есть преимущество (защита от фрагментации). - person Roman Starkov; 30.04.2014
comment
@romkyns Вопрос не предполагает, что 10 ГБ виртуальной памяти — это плохо. Когда вы объясняете, почему это не плохо, это просто проповедь хору. Вопрос только в том, почему Java имеет 10 ГБ в качестве значения по умолчанию. - person Navin; 06.05.2014

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

Если приложение видит виртуальное адресное пространство размером 10 ГБ, все, что оно сигнализирует приложению, это то, что оно может использовать адреса памяти до 10 ГБ, если захочет. Тем не менее, память фактически не выделяется в физическом ОЗУ до тех пор, пока она не будет фактически записана, и это делается на постраничной основе, где страница представляет собой раздел памяти размером 4 КБ. Виртуальное адресное пространство — это просто виртуальное пространство, пока оно не используется.

Допустим, приложению выделено 10 ГБ адресного пространства, и оно начинает использовать часть из них. Поскольку сначала записывается «свежая» — ранее нетронутая — страница этой виртуальной памяти, система на низком уровне «сопоставляет» эту виртуальную страницу с разделом физической памяти, а затем записывает ее. Но самому этому приложению не нужно беспокоиться о таких деталях, оно просто действует так, как будто оно имеет полный доступ к виртуальной области памяти.

В случае Java-приложений это адресное пространство выделяется не самому приложению, а Java, и Java по умолчанию просто запрашивает огромное адресное пространство — количество, которое оно запрашивает, рассчитывается относительно размера физической памяти, а не потому, что оно имеет любой должен быть консервативным, но только для практичности - приложению вероятно не понадобится достаточный размер кучи, чтобы полностью поставить сервер на колени, поэтому оно работает, исходя из предположения, что этого не произойдет. Как я сказал выше, это не означает, что так много «распределено» или что системе пришлось затратить на это много ресурсов.

person thomasrutter    schedule 30.04.2014

Это не ваша программа использует эту память, это виртуальная машина Java резервирует эту память, независимо от того, какая программа загружена.

person Pieter B    schedule 29.04.2014
comment
Нет, он говорит, что может использовать эту сумму, но (пока) не использует ее. - person Volker Siegel; 30.04.2014
comment
Почему у этого неправильного ответа так много голосов. Виртуальная машина Java не использует столько памяти. Он выделил только столько виртуального адресного пространства. Это не имеет ничего общего с тем, сколько памяти используется. - person thomasrutter; 30.04.2014
comment
@thomasrutter исправил, сказав «зарезервировать» вместо «использовать». Этот ответ правильный, потому что программа hello-world вообще ничего не делает. Это делает виртуальная машина Java, и программа hello-world выполняется виртуальной машиной. Это различие важно и не ставится в вопросе. - person Pieter B; 30.04.2014
comment
Это все еще не правильно. Он не резервирует никакой памяти. Он представляет собой виртуальное адресное пространство определенного размера. В этот момент память не резервируется и не выделяется. Это действительно виртуальное адресное пространство. На самом деле это не отражает реальную память. - person thomasrutter; 30.04.2014
comment
Действительно, Томасруттер прав: ключевое различие не между выделенной и зарезервированной памятью, а между памятью и адресным пространством, что немного более абстрактно. - person Jules; 01.05.2014

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

Городской объект - главное воспоминание. Склад — это дисковое пространство.

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

person Russell Borogove    schedule 30.04.2014
comment
Я бы даже сказал, что не печатает. Больше похоже на резервирование права на печать непрерывных этикеток 10B для клиента. - person Patrick Huizinga; 01.05.2014
comment
Ну, вы можете возразить, что есть определенная степень приверженности — например. таблицы страниц, как упоминалось в других сообщениях. - person Russell Borogove; 01.05.2014

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

person Audrius Meskauskas    schedule 30.04.2014

Ваша программа НЕ использует так много памяти. JVM/OS резервирует эту память, т. е. предел, который может использовать ваша программа. Кроме того, как ясно упоминает один из ответов. 32-битные и 64-битные не имеют к этому никакого отношения. 32-разрядная версия означает, что вы можете получить доступ к 2^32 ячейкам физической памяти. а 64 бит означает до 2^64.

person TheLostMind    schedule 30.04.2014