java -Xmx1G 的意思是 10^9 还是 2^30 字节?

2022-09-01 03:07:18

一般来说,单位是用于,和选项(“k”,“M”和“G”,或不太标准的可能性“K”,“m”或“g”)二进制前缀倍数(即1024的幂),还是1000的幂?-Xmx-Xms-Xmn

手册说它们代表千字节(kB),兆字节(MB)和千兆字节(GB),这表明它们是原始SI系统中定义的1000的幂。我的非正式测试(我对此不是很有信心)表明它们实际上是千字节(kiB),兆字节(MiB)吉比字节(GiB),都是1024的幂。

那么哪个是正确的呢?例如,什么Java代码会显示当前的大小?

对于RAM大小,使用1024的倍数并不奇怪,因为RAM通常是通过加倍硬件模块来物理布局的。但是,随着我们获得越来越大的权力,以清晰和标准的方式使用单位变得越来越重要,因为混淆的可能性越来越大。我的JVM也接受单位“t”,1 TiB比1 TB大10%。

注意:如果这些真的是二进制倍数,我建议更新文档和用户界面以非常清楚地说明这一点,例如“附加字母k或K以指示千字节(1024字节),或m或M表示兆字节(1048576字节)”。这就是所采用的方法,例如,在Ubuntu:UnitsPolicy - Ubuntu Wiki中。

注意:有关这些选项的用途的更多信息,请参阅例如java - 启动JVM时的Xms和Xmx参数是什么?


答案 1

简短回答:JVM 命令行参数使用的所有内存大小都以传统的二进制单位指定,其中 1 千字节为 1024 字节,其他的则以 1024 的幂递增。

长答案:

命令行参数上的此文档页面指出,以下内容适用于所有接受内存大小的参数:

例如,若要将大小设置为 8 GB,可以指定 、 、 或 作为参数。8g8192m8388608k8589934592

对于 ,它给出了这些具体的例子:-Xmx

以下示例显示如何使用各种单位将分配内存的最大允许大小设置为 80 MB:

-Xmx83886080
-Xmx81920k
-Xmx80m

在我想检查文档之前(我假设你已经有了?),我检查了HotSpot的源代码,发现内存值在src / share / vm / runtime /arguments中解析.cpp由函数解析(这似乎代表“ASCII到内存,无符号长长”):atomull

// 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;
  }
}

这些常量 , 在 src/share/vm/utilities/globalDefinitions.hpp 中定义:KMG

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

所有这些都证实了文档,除了对TB后缀的支持显然是后来添加的,并且根本没有记录。T

使用单位乘法器不是强制性的,因此,如果您想要十亿字节,则可以编写 。如果您确实使用乘法器,则它们是二进制的,因此意味着230字节,或一个内存。-Xmx1000000000-Xmx1G

(这并不奇怪,因为Java早于IEC试图追溯性地重新定义现有单词。如果IEC只是建议在偶尔的含义不清楚的情况下用限定词“二进制”和“十进制”来消除存储单元的歧义,则可以节省混淆。例如,二进制千兆字节 (GB2) = 10243 字节,十进制千兆字节 (GB10) = 10003 字节。但是不,他们重新定义了每个人都已经在使用的词,不可避免地爆发了混乱,让我们陷入了这些小丑术语“gibibyte”,“tebibyte”和其他术语中。哦,上帝保佑我们。


答案 2

您有两种方法可以获得问题的答案:

a) 检查 JDK 的源代码。对不起,我无法在5分钟内谷歌它。

b)编写一个模拟,运行几次并进行一些观察。

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近似值。


推荐