Java 64 位版本比 32 位版本使用更多内存

Java 64 bit uses more memory than a 32 bit version

我正在测试我的 java 应用程序,我注意到 Java 64 位版本比在 Java 32 位版本中执行应用程序使用更多。

我测试的服务器是 Windows 7-64 位和 Solaris-64 位,但在这两种情况下都发生了相同的行为。顺便说一下,应用程序使用默认 VM 参数运行,Java 使用的版本是 8u65s。

因为我的服务器是 64 位的,所以正确的选择应该是 Java 64 位,但这有什么原因吗?在什么情况下 32 位版本优于 64 位版本?

两者分配的内存:

32-bit : 74mb
64-bit: 249mb

这是 Java(以及 Microsoft .NET)的正常行为,主要是因为它们的指针模型以及垃圾收集模型。

对象变量实际上是指向堆上对象的指针。在 64 位版本中,此指针需要两倍 space。因此,存储在容器中的指针将需要更多内存,垃圾收集器持有以允许收集的指针也将如此。由于对象主要由指向其他对象的指针组成,因此 32 位和 64 位之间的差异加起来非常快。

除此之外,垃圾收集器必须有效地跟踪所有这些对象,在 64 位版本中,收集器倾向于使用更大的最小分配大小,因此它不必跟踪尽可能多的内存片。这是有道理的,因为无论如何对象都更大。我相信最小大小通常在 32 位模式下为 16 字节,在 64 位模式下为 32 字节,但这些完全取决于您使用的特定虚拟机,因此它们会有所不同。

例如,如果您有一个只需要 12 字节堆内存的对象,而您 运行 在最小分配大小为 32 字节的虚拟机上,它将使用 32 字节,其中 20 个字节被浪费了。如果您在最小大小为 16 字节的机器上分配同一个对象,它将使用 16 个字节,其中 4 个被浪费。替代方法是在跟踪这些块时浪费更多内存,因此这实际上是最好的方法,并且可以使您的应用程序的性能和资源利用率保持平衡。

另一件要记住的事情是 Java 运行时从操作系统为其堆分配内存块,然后程序可以从这些块中分配内存。运行时试图保持领先于您的程序的内存需求,因此它会分配比需要更多的内存并让您的程序增长。具有更高的最小分配大小,64 位运行时将为其堆分配更大的块,因此与 32 位运行时相比,您将拥有更多未使用的内存。

如果内存消耗对您的特定应用程序来说是一个严重的限制,您可以考虑使用本机编译的 C++(使用实际的 C++ 标准,而不是带有对象指针的遗留 C!)。原生 C++ 通常需要 Java 的 1/5 内存来完成同样的事情,这就是原生代码在移动设备上更受欢迎的原因(C++ 和 Objective C)。当然,C++ 有它自己的问题,所以除非你迫切需要减少内存消耗,否则最好接受这是正常行为并继续使用 64 位 Java.

64位内存模型占用内存多是正确的

此外,我只是想提一个 Solaris 问题,所以这并不是您问题的完整答案,但下面的答案可以充分解释您看到的 74mb 和 249mb 之间的区别。

正确的是,Solaris 不再有 32 位版本 Java,Mac OS X 也是如此。请注意 Java 7 在 Solaris 上你会 总是 获得 32 位 Java(即使你安装了 64 位 Java)除非你 明确 使用 -d64 标志请求 64 位。所以一定不要在这里比较苹果和橘子。很多 Solaris 用户 认为 他们已经 运行 64 位 Java 因为他们已经安装了它,却没有意识到必须明确要求它。

对于 Solaris 上的 Java 8,没有必要指定 -dXX,因为只有 64 位版本。

因此 - 仅仅由于此 - 内存设置的默认值已更改。我要说的是 仅仅是因为这个(而不是关于内存指针的讨论),你的 Java 8 在 Solaris 上似乎正在从 OS. 这其实是海市蜃楼.

以下是 16 GB 系统的回顾(值将根据您安装的 RAM 量而变化):

Java Solaris 上的 7

在没有更多命令行选项的 Solaris 上使用 Java 7,您将获得 32 位内存模型(即使安装了 64 位版本也暗示了 -d32)和默认值如下:

memory model:  32 bit
-Xms default :  64 MB
-Xmx default :   1 GB

如果您明确使用 -d64,您将得到:

memory model:  64 bit
-Xms default :  256 MB
-Xmx default :   4 GB

Java Solaris 上 8

在 Solaris 上使用 Java 8,如果没有更多命令行选项,您将获得 64 位内存模型(隐含 -d64-d32 现在是非法的)和默认值为如下:

memory model:  64 bit
-Xms default :  256 MB
-Xmx default :   4 GB

关于您已阅读的评论:"SPARC is on the order of 10-20% degradation when you move to a 64-bit VM"。我对此表示怀疑。我可以看到您已经阅读了它 here 但该文档适用于 Java 1.4 并且可能适用于 Java 5。从那以后发生了很多事情。