Означает ли java -Xmx1G 10 ^ 9 или 2 ^ 30 байт?

И вообще, используются ли единицы для вариантов -Xmx, -Xms и -Xmn ("k", "M" и "G" или менее стандартные варианты "K", "m" или "g") Двоичный префикс кратен (т.е. степени 1024) или степени 1000?

В руководствах говорится, что они представляют килобайты (кБ), мегабайты (МБ) и гигабайты (ГБ), предполагая, что они являются степенью 1000, как определено в исходном СИ. Мои неофициальные тесты (в которых я не очень уверен) показывают, что они действительно составляют кибибайты (киБ). , мебибайты (МиБ) и гибибайты (ГиБ), все степени числа 1024.

Так что же правильно? Например. какой код Java покажет текущий размер?

Использование числа, кратного 1024, неудивительно для размеров ОЗУ, поскольку ОЗУ обычно физически размещается путем удвоения аппаратных модулей. Но использование единиц четким и стандартным способом становится все более важным по мере того, как мы получаем все большие и большие мощности, поскольку растет вероятность путаницы. Единица «t» также принимается моей JVM, а 1 ТиБ на 10% больше, чем 1 ТБ.

Примечание: если это действительно двоичные числа, я предлагаю обновить документацию и пользовательские интерфейсы, чтобы четко указать на это, добавив такие примеры, как «Добавить букву k или K для обозначения кибибайт (1024 байта), или m или M для указать мегабайты (1048576 байт)". Такой подход используется, например, в Ubuntu: UnitsPolicy — Ubuntu Wiki.

Примечание. Подробнее о том, для чего используются параметры, см., например. java — каковы параметры Xms и Xmx при запуске JVM ?.


person nealmcb    schedule 30.09.2015    source источник
comment
@ElliottFrisch В основном я задаю вопрос, ища окончательный ответ. Предложение по документации просто предназначено для того, чтобы добавить больше ясности в то, что меня смущает.   -  person nealmcb    schedule 30.09.2015


Ответы (3)


Краткий ответ: все размеры памяти, используемые аргументами командной строки JVM, указываются в традиционных двоичных единицах, где килобайт равен 1024 байтам, а остальные увеличиваются до степени 1024.

Длинный ответ:

На этой странице документации по аргументам командной строки говорится, что следующее относится ко всем аргументы, принимающие размеры памяти:

Например, чтобы установить размер 8 ГБ, вы можете указать в качестве аргумента 8g, 8192m, 8388608k или 8589934592.

Для -Xmx он дает следующие конкретные примеры:

В следующих примерах показано, как установить максимально допустимый размер выделенной памяти равным 80 МБ, используя различные единицы измерения:

-Xmx83886080
-Xmx81920k
-Xmx80m

Прежде чем я решил проверить документацию (я полагал, что у вас уже есть?), я проверил исходный код HotSpot и обнаружил, что значения памяти анализируются в src/share/vm/runtime/arguments.cpp функцией atomull (которая, кажется, означает "ASCII для память, unsigned long long"):

// Parses a memory size specification string.
static bool atomull(const char *s, julong* result) {
  julong n = 0;
  int args_read = sscanf(s, JULONG_FORMAT, &n);
  if (args_read != 1) {
    return false;
  }
  while (*s != '\0' && isdigit(*s)) {
    s++;
  }
  // 4705540: illegal if more characters are found after the first non-digit
  if (strlen(s) > 1) {
    return false;
  }
  switch (*s) {
    case 'T': case 't':
      *result = n * G * K;
      // Check for overflow.
      if (*result/((julong)G * K) != n) return false;
      return true;
    case 'G': case 'g':
      *result = n * G;
      if (*result/G != n) return false;
      return true;
    case 'M': case 'm':
      *result = n * M;
      if (*result/M != n) return false;
      return true;
    case 'K': case 'k':
      *result = n * K;
      if (*result/K != n) return false;
      return true;
    case '\0':
      *result = n;
      return true;
    default:
      return false;
  }
}

Эти константы K, M, G определены в src/share/vm/utilities/globalDefinitions.hpp:

const size_t K                  = 1024;
const size_t M                  = K*K;
const size_t G                  = M*K;

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

Не обязательно использовать множитель единиц, поэтому, если вам нужен один миллиард байтов, вы можете написать -Xmx1000000000. Если вы используете множитель, он двоичный, поэтому -Xmx1G означает 230 байт или одну планку ОЗУ.

(Что на самом деле неудивительно, потому что Java предшествовала попытке IEC задним числом переопределить существующие слова. Путаницу можно было бы избежать, если бы IEC просто посоветовал устранять неоднозначность единиц памяти с помощью квалификаторов «двоичный» и «десятичный» время от времени их значение было неясным. Например, двоичные гигабайты (ГБ2) = 10243 байта и десятичные гигабайты (ГБ10) = 10003 байт. Но нет, они переопределили слова, которые все уже использовали, неизбежно взорвав путаницу и заставив нас застрять с этими клоунскими терминами "гибибайт". ", "тебибайт" и прочее. Господи, избавь нас.)

person Boann    schedule 30.09.2015
comment
Спасибо, что нашли код! Очень ясно. Но я должен отметить, что именно компьютерщики переопределили ранее однозначные термины, которым более двух веков. Для IEC сохранить их в том виде, в котором они использовались так долго, и предоставить новые термины для новых единиц, для меня есть большой смысл. MiB гораздо менее громоздкий и гораздо легче форматируется, переводится и т. д., чем двоичный мегабайт или MB_2. - person nealmcb; 30.09.2015
comment
Спасибо, что нашли эту документацию. В нем есть гораздо более четкие примеры, поясняющие использование МБ и ГБ, чем документация, которую я нашел в своей системе (Ubuntu) и в своих веб-поисковиках. Похоже, они это уточнили, возможно, для Java 8 :) - person nealmcb; 30.09.2015
comment
Для Oracle Java 8 ситуация странная. Настройка -Xmx8g заканчивается maxMemory размером 7,11 ГБ (7635730432 байта)... С Java 11 я получаю полные 8 ГБ. - person Robert; 19.01.2019

У вас есть два варианта получить ответ на свой вопрос:

а) проверить исходный код JDK. Извините, я не смог загуглить его за 5 минут.

б) написать симуляцию, запустить ее несколько раз и сделать некоторые наблюдения.

public class A {
  public static void main(String[] args) throws Exception {
    System.out.println("total: " + Runtime.getRuntime().totalMemory());
  }
}

И запустите его несколько раз:

java -Xms130m -Xmx2G A
total: 131072000
java -Xms131m -Xmx2G A
total: 132644864
java -Xms132m -Xmx2G A
total: 132644864
java -Xms133m -Xmx2G A
total: 134742016
java -Xms134m -Xmx2G A
total: 134742016

Итак, обоснованное предположение состоит в том, что java использует не точное число, а 2 ^ n приближение запрошенного вами числа.

person ya_pulser    schedule 30.09.2015

В другом вопросе о флаге -Xmx Runtime.getRuntime().maxMemory() используется для показать текущий размер. Также отмечается, что -Xmx1024m и -Xmx1g приводят к идентичному результату, указывая на то, что числа являются степенями двойки, а не десяти.

Обратите также внимание на разницу между totalMemory() и maxMemory().
Что такое Runtime.getRuntime().totalMemory() и freeMemory()?

person jaco0646    schedule 30.09.2015
comment
Вопрос, на который вы ссылаетесь, является точным! Ознакомьтесь, в частности, с классом MemTest от Алекса для полного учета памяти без кучи (включая Code Cache и Perm Генпулы) по сравнению с динамической памятью (включая Eden Space, Survivor space и Tenured генпулы) - person nealmcb; 30.09.2015