Java 一个简单的;“你好,世界”;64位机器需要10G虚拟内存,而32位机器需要1G虚拟内存?

Java 一个简单的;“你好,世界”;64位机器需要10G虚拟内存,而32位机器需要1G虚拟内存?,java,memory-management,jvm,64-bit,virtual-memory,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

在我们的生产机器上运行一个简单的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
有人知道为什么会这样吗

联阿援助团说:

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内存,新机器有32GB内存。

这些内存被定义为机器物理内存的一个百分比,现在生产服务器往往拥有大量物理内存


您可以通过选择两者。

不是您的程序耗尽了内存,而是Java虚拟机保留了内存,不管加载了哪个程序。

虚拟内存对您来说真的不重要

32位和64位的基本区别在于64位的地址空间非常大。如果您觉得10Gib的内存量很大,请注意,64位上的.NET可以像这样使用TIB内存。然而,在32位上,.NET要保守得多(JVM也是如此)——地址空间总共是4Gib——这并不多

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

关键是,内存的物理位置不一定是连续的,但这是在您力所能及的范围之外完成的,而且映射通常非常快。另一方面,比如说,索引一个数组,它实际上是由10个不同的虚拟地址内存块组成的,这是(完全不必要的)工作

所以你就有了它-虚拟内存在64位上几乎是空闲的。基本方法是“如果有,就使用”。您没有限制其他应用程序,而且如果您最终真的使用了它,它会为您节省大量的工作。但在那之前,你只有一个预约。它根本不会转换成任何物理内存。你不必为今晚可能来坐在你桌边的朋友付钱,但如果他们真的来了,你仍然有空间让他们坐下来——只有当他们最终来了,你才真正得到“收费”

有关Java在不同机器和不同版本上的行为方式的更多信息,请参见此问题:
最大堆大小还决定保留的虚拟内存量,因为堆必须是一个连续的地址空间。如果没有预先保留,堆可能无法扩展到此最大值,因为其他人在堆必须扩展的位置保留了一个地址空间区域。

事实证明,在使用虚拟内存寻址的现代计算机体系结构上(其中“内存空间”应用程序实际上与实际分配的内存无关),它实际上与在启动时为应用程序提供多少虚拟“内存空间”无关。这并不意味着系统已经分配了这么多内存

如果应用程序看到一个10GB的虚拟地址空间很大,那么它向应用程序发出的所有信号是,如果需要,它可以使用最高10GB的内存地址。然而,在实际写入内存之前,不会在物理RAM中实际分配内存,这是在逐页的基础上完成的,其中一页是内存的4kB部分。虚拟地址空间在实际使用之前是完全虚拟的

假设一个应用程序有10GB的地址空间,它开始使用其中的一部分。当这个虚拟内存的一个“新的”(以前未接触过的)页面首先被写入时,系统将在较低的级别上“映射”这个虚拟页面到物理内存的一部分,然后再写入它。但该应用程序本身不必担心这些细节,它的行为就好像它可以完全访问虚拟内存区域一样


在Java应用程序的情况下,分配地址空间的不是应用程序本身,而是Java,Java默认情况下只是请求一个巨大的地址空间——它请求的数量是相对于物理内存大小计算的,但不是因为它需要保守,但仅仅出于实用性考虑——应用程序可能不需要足够大的堆来让服务器完全崩溃,所以它是在假设不会的情况下运行的。正如我在上面所说的,这并不意味着有这么多的内存被“分配”,也不意味着系统必须为此花费大量资源。

您的程序没有使用这么多内存。JVM/OS正在保留该内存,即程序可以使用的限制。还有,就像其中一个答案明确提到的。32位和64位与此无关。32位意味着您最多可以访问2^32个物理内存位置。64位意味着最多2^64。

假设您从事文档存储业务。你有一个小的设施在城市的中间,储存纸箱,和一个更大的仓库在城外1000倍的空间。每个盒子上都有一个标签,标明里面的东西

市内设施是主存储器。仓库是磁盘空间


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

这不是应用程序实际使用的物理内存量。虚拟内存