一个简单的“Hello World”需要64位机器上的10G虚拟内存与32位上的1G虚拟内存?

在我们的生产机器上运行一个简单的Java程序,我注意到这个程序吃了更多的10G virt。 我知道虚拟内存是不相关的,但至less我想明白为什么这是必要的。

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

下面是什么当我运行这个小程序时说的:

  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。 旧机器有4GB RAM,新的32GB。

初始堆和最大堆的默认大小被定义为机器物理内存的百分比,现在的生产服务器往往有一大堆

您可以通过-Xms和-Xmx命令行选项来select这两个选项 。

虚拟内存对你来说并不重要。

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

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

重点是,内存的物理位置不一定是连续的,但这是在你的范围之外完成的,并且映射通常非常快。 另一方面,不得不说,索引一个数组,这实际上是分割了超过10个不同的虚拟地址内存块,这是(完全不必要)的工作。

所以你有它 – 虚拟内存在64位上几乎是免费的。 基本的方法是“如果它在那里,使用它”。 你不限制其他应用程序,如果你真的最终使用它,它可以节省很多工作。 但直到这一点,你只有一个保留。 它根本不会转换成任何物理内存。 你不用为今晚可能来的朋友付钱,而是坐在你的桌子旁边,但是如果他们来的话,你仍然有空间坐下来 – 只有当他们终于到来的时候,你才会真正被“收费”。

有关Java在不同机器和不同版本上的行为方式的更多信息,请参阅此问题: Java SE 6中Sun Java虚拟机的默认最大堆大小是多less? 最大堆大小还决定了保留的虚拟内存量,因为堆必须是连续的地址空间。 如果没有预先保留,可能会发生堆不能扩展到这个最大值,因为有人在堆必须扩展的地方保留了一个地址空间区域。

不是你的程序占用了内存,而是Java VM保留这个内存,而不pipe哪个程序被加载。

事实certificate,在使用虚拟内存寻址的现代计算机体系结构(应用程序看到的“内存空间”实际上并不涉及实际物理分配的内存)的情况下,这个虚拟“内存空间“是在启动时给予应用程序的。 这并不意味着这个内存已经被系统分配了。

如果一个应用程序看到一个10GB大的虚拟地址空间,那么它向应用程序发出的信号就是它可能会使用高达10GB的内存地址。 然而,内存实际上并没有分配到物理内存中,直到它实际写入,而且这是在一页一页的基础上完成的,其中一页是一个4kB的内存部分。 虚拟地址空间就是这样 – 在实际使用之前是完全虚拟的。

假设一个应用程序被赋予了10GB的地址空间,并开始使用它的一部分。 当虚拟内存的“新鲜”(先前未触及的)页面首先被写入时,系统将在低级别上将该虚拟页面“映射”到物理内存的一部分,然后写入它。 但是,这个应用程序本身并不需要担心这些细节,它只是充当了对虚拟内存区域的访问。

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

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

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

想象一下,你在文档存储业务。 你在城市中间有一个小型的设施,可以存放一些文件,还有一个比1000倍的空间大得多的仓库。 每个盒子上都有一个标签来标识其内容。

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

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