【问题标题】:A simple "Hello World" needs 10G virtual memory on a 64-bit machine vs 1G at 32-bit?一个简单的“Hello World”在 64 位机器上需要 10G 虚拟内存,而在 32 位机器上需要 1G?
【发布时间】:2014-04-29 09:59:27
【问题描述】:

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

在较旧的 32 位 Linux 机器上,相同的程序仅消耗大约 1G virt。旧机器有 4GB 内存,新机器有 32GB。

【问题讨论】:

  • @CurtisHx:想想看。 1 GB 的虚拟内存!还是疯了,这么大的地址空间干什么?
  • @MSalters 为托管堆预分配(不提交)空间。这是 64 位的世界,你可以拥有尽可能多的虚拟空间,这实际上并不重要。
  • @MSalters 是 JVM,而不是预先分配所有地址空间的 Hello World 代码。
  • 我认为这可能是我见过的第一个问题,它在 StackOverflow 上可能比它发布的地方更合适......哈哈。
  • @a_horse_with_no_name:我的意思是预订本身加起来有几兆字节。这是 UNIX 风格编程的一个问题,您可能有成千上万的小进程并存。如果整个过程只是一个兆字节,那没问题。

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


【解决方案1】:

default sizes for initial heap and maximum heap 被定义为机器物理内存的百分比,如今生产服务器往往拥有很多

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

【讨论】:

  • 等等。 > 最大堆大小:物理内存的 1/4 或 1GB 中的较小者 - 因此默认最大堆的上限为 1 GB。假设这没有改变,你是说初始分配高于最大值吗?因为这听起来很糟糕。
  • @Bob 似乎这仅适用于客户端 VM 上的 32 位 Java 和 1.6 之前的 64 位。服务器 VM 上的 Java 1.6+ 64 位愉快地保留了更多。
  • @Bob:“注意:为 Java SE 5.0 提供的堆大小的边界和分数是正确的。随着计算机变得越来越强大,它们在后续版本中可能会有所不同。”
【解决方案2】:

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

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

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

关键是,内存的物理位置不一定是连续的,但这是在您无法触及的范围内完成的,而且映射通常非常快。另一方面,不得不索引一个数组,该数组实际上被分割为 10 个不同的虚拟地址内存块,这是(完全没有必要的)工作。

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

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

【讨论】:

  • @gnat 怎么样? It creates a contiguous address space for the VM to use, which means that you don't have to fragment the heap 对我来说似乎是一个非常明确的理由。并且我已经解释了 32 位和 64 位环境之间的区别。
  • @gnat 确实如此,通过解释问题的前提(10G 的虚拟地址空间在某种程度上不好或不受欢迎)是错误的,并且有一个好处(防止碎片化)。
  • @romkyns 问题确实假定 10GB 的虚拟内存不好。当你解释为什么它不坏时,那只是在向合唱团讲道。问题只是问为什么 Java 有 10GB 作为默认值。
【解决方案3】:

事实证明,在使用虚拟内存寻址(其中应用程序看到的“内存空间”实际上与实际物理分配的内存无关)的现代计算机架构上,它确实没有不管这个虚拟“内存空间”有多少是在启动时分配给应用程序的。这并不意味着系统已经分配了这么多内存。

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

假设一个应用程序有 10GB 的地址空间,它开始使用其中的一些空间。作为首先写入此虚拟内存的“新” - 先前未触及的 - 页面,系统将在低级别上将此虚拟页面“映射”到物理内存的一部分,然后将其写入。但是该应用程序本身不必担心这些细节,它只是表现得好像它可以完全访问内存的虚拟区域。

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • 不,它是说它可能使用那个数量,而不是(还)使用它。
    • 为什么这个不正确的答案有这么多赞成。 Java VM 没有“使用”那么多内存。它只分配了那么多的虚拟地址空间。这与“使用”多少“内存”无关。
    • @thomasrutter 更正为保留而不是使用。这个答案是正确的,因为 hello-world 程序根本不做任何事情。是 Java VM 做的,并且 hello-world 程序由 VM 执行。这种区别很重要,不会在问题中提出。
    • 还是不正确。它不是“保留”任何内存。它呈现了一个特定大小的虚拟地址空间。此时内存不是“保留”或“分配”的。它确实是“虚拟”地址空间。它并不能真正反映实际内存。
    • 确实,thomasrutter 是正确的:关键的区别不是分配的内存和保留的内存,而是内存和地址空间之间的区别,这有点抽象。
    【解决方案5】:

    假设您从事文档存储业务。您在城市中心有一个小型设施,用于存储成箱的文件,在城外有一个更大的仓库,空间是其 1000 倍。每个盒子上都有一个标签来标识它的内容。

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

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

    【讨论】:

    • 我什至不打印。更像是保留为客户打印 10B 连续标签的权利。
    • 好吧,你可以争辩说有一定程度的承诺正在做——例如。页表,正如其他帖子所提到的那样。
    【解决方案6】:

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

    【讨论】:

      【解决方案7】:

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

      【讨论】:

        猜你喜欢
        • 2011-09-04
        • 1970-01-01
        • 2012-01-16
        • 2017-02-16
        • 1970-01-01
        • 1970-01-01
        • 2011-08-08
        • 2011-04-09
        • 1970-01-01
        相关资源
        最近更新 更多