一个简单的" Hello World"在64位机器上需要10G虚拟内存而在32位机器上需要1G吗?

时间:2014-04-29 09:59:27

标签: java memory-management jvm 64-bit virtual-memory

在我们的生产机器上运行一个简单的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

在较旧的32bit-linux机器上,同一程序仅耗费约1G virt。旧机器有4GB RAM,新机器有32GB。

7 个答案:

答案 0 :(得分:86)

default sizes for initial heap and maximum heap被定义为机器物理内存的百分比,现在生产服务器往往拥有一大堆

您可以通过-Xms and -Xmx command line options选择两者。

答案 1 :(得分:46)

虚拟内存对你来说无关紧要。

32位和64位之间的基本区别在于64位的地址空间非常大。如果10 GiB看起来很多,请注意64位上的.NET可以像这样使用内存的TiB。然而在32位上,.NET更加保守(JVM也是如此) - 地址空间为4 GiB 总计 - 这并不是很多。

但这无关紧要 - 没关系。这只是一个大大简化编程的事情,并且对主机操作系统没有任何负面影响。它为VM创建了一个连续的地址空间,这意味着你不必分割堆(或者更糟的是,堆栈,它或多或少是不可能的 - 但那些往往只是一个MiB左右)你需要更多的“真实”记忆。当你最终提交虚拟内存时,它会变得更加真实 - 在这一点上,它或多或少必须由某些数据存储支持 - 无论是页面(交换)文件还是物理RAM。

关键是,内存的物理位置不一定是连续的,但这是在您的范围之外完成的,并且映射通常非常快。另一方面,不得不对数组进行索引,这实际上是在10个不同的虚拟地址内存块上进行分段,这是(完全不必要的)工作。

所以你有它 - 虚拟内存在64位上几乎是免费的。基本方法是“如果它在那里,使用它”。您不限制其他应用程序,如果 实际上最终使用它,它可以为您节省大量工作。但在此之前,您只能预订。它根本不会转换为任何物理内存。你没有为今晚可能来的朋友付钱,坐在你的餐桌旁,但是如果他们来的话,你还有空间让他们坐下来 - 只有当他们最终来的时候,你才真正得到“收费”。

有关Java在不同计算机上使用不同版本的行为方式的详细信息,请参阅此问题:What is the default maximum heap size for Sun's JVM from Java SE 6? 最大堆大小也决定了保留的虚拟内存量,因为堆必须是连续的地址空间。如果它没有预先保留,则可能发生堆无法扩展到此最大值,因为其他人在堆必须扩展的位置保留了一个地址空间区域。

答案 2 :(得分:7)

不是你的程序占用了那个内存,它是保留该内存的Java VM,无论加载哪个程序。

答案 3 :(得分:7)

事实证明,在使用虚拟内存寻址的现代计算机体系结构中(应用程序看到的"内存空间"实际上与实际的内存无关>物理分配),这个虚拟"内存空间"的确无关紧要。在启动时给予应用程序。它并不意味着系统已分配了这么多内存。

如果应用程序看到一个10GB的虚拟地址空间,它向应用程序发出的信号是可能使用最大10GB的内存地址(如果需要)。但是,在实际写入内存之前,内存实际上并未在物理RAM中分配,这是在逐页的基础上完成的,其中页面是4kB的内存部分。虚拟地址空间就是这样 - 在实际使用之前完全虚拟。

让我们说应用程序有10GB的地址空间,并开始使用其中一些。作为一个新鲜的" - 先前未触及 - 首先写入此虚拟内存的页面,系统将在较低级别上映射" map"这个虚拟页面到一段物理内存,然后写出来。但是,该应用程序本身不必担心这些细节,它只是表现为可以完全访问虚拟的内存区域。

对于Java应用程序,它不是应用程序本身,而是分配了地址空间的Java,而Java默认只是请求一个巨大的地址空间 - 它请求的数量是相对于物理内存计算的大小,但不是因为它有任何需要保守,但仅仅是为了实用性 - 一个应用程序可能不希望足够的堆大小完全使服务器瘫痪,所以它'以它赢得的假设运作。正如我上面所说的,这并不意味着这么多就被分配了#34;或者系统不得不花费很多资源。

答案 4 :(得分:3)

想象一下,您正处于文档存储业务中。您在市中心有一个小型设施,可以存放纸箱,还有一个位于城外的大型仓库,占地面积的1000倍。每个盒子上都有一个标签,标明其内容。

城市设施是主要记忆。仓库是磁盘空间。

为新流程分配10GB虚拟内存并不意味着为新客户找到100亿个盒子的空间。这意味着为具有连续ID号的盒子打印100亿个标签

答案 5 :(得分:3)

这不是应用程序实际使用的物理内存量。所有进程使用的虚拟内存可以比机器上的物理RAM数量多出几个数量级,没有任何明显的问题。

答案 6 :(得分:2)

你的程序没有使用这么多内存。 JVM / OS保留了该内存,即程序可以使用的UPTO限制。另外,像其中一个答案清楚地提到。 32位和64位与此无关。 32位意味着您可以访问最多2 ^ 32个物理内存位置。和64位意味着最多2 ^ 64。