JRE 32位与64位的区别

14

我已经使用Java有一段时间了,设置新的开发机器通常需要从Oracle网站下载和安装最新版本的JDK。

这引发了一个不寻常的问题:使用32位或64位的JRE包有什么影响吗?

回想一下,我之前安装过两个版本,并且我的常规工具链(Eclipse)可以很好地适应。在日常编程中,我不记得曾经因为使用64位JRE(或针对64位JRE)而改变或考虑过任何事情。

根据我对64位和32位的了解,它实际上归结为数字在内部的存储方式...我知道int是32位和long是64位...同样float是32位和double是64位--所以是不是Java已经将这种微妙的差别抽象化了,也许一直以来都是“64位兼容”的呢?

当然,除了无法在32位系统上安装64位JRE之外,我肯定还漏掉了某些东西。


3
在32位的JVM中,你只能将-Xmx设置为小于4GB,但在64位的情况下,唯一的限制是硬件/虚拟内存。 - Jim Garrison
2
@JimGarrison 我认为这也进一步取决于操作系统。在Windows上使用32位JRE,我认为最大堆大小应该小于2GB。 - Kevin Hooke
1
Windows的限制更多:https://dev59.com/5HM_5IYBdhLWcg3wThN3。 - wumpz
1
@wumpz:我认为你说的是32位Windows,而不是64位Windows上的32位JVM。如果您有超过2GB左右的物理内存,那么您肯定希望使用64位操作系统,因为如果它不能将所有内存一次性映射到内核地址空间中,而必须在需要时播放不同的页面来映射,则会使操作系统效率降低。 - Peter Cordes
5个回答

24

64位和32位实际上是指对象引用的大小,而不是数字的大小。

在32位模式下,引用大小为4字节,允许JVM独立寻址2^32个字节的内存。这就是为什么32位JVM最大堆大小被限制为4GB的原因(实际上,由于其他JVM和操作系统开销的影响,限制可能更小,并且取决于操作系统)。

在64位模式下,引用大小为8字节,允许JVM独立寻址2^64个字节的内存,应该足够了吧。64位模式下指定的JVM堆大小(使用-Xmx参数)可以非常大。

但是,使用64位模式会带来成本:引用大小加倍,增加了内存消耗。这就是为什么Oracle引入了"压缩oop"。启用压缩oop(我相信现在是默认设置)后,对象引用将缩小至4字节,但堆被限制为40亿个对象(和32GB Xmx)。压缩oop并非免费:实现这一巨大的减少内存消耗的计算成本很小。

作为个人偏好,我总是在家中运行64位的JVM。CPU具备x64能力,操作系统也是如此,因此我喜欢JVM也以64位模式运行。

1
刚启动的Netbeans与我的项目集在x32 Java8上使用了600MB,而在x64 JVM上启动相同的东西使用了1180MB - 多了一倍。这就是为什么我个人偏好于使用x32 JVM,除非内存使用量大致超过-Xmx1200,这是JVM能够分配的最大堆大小(根据主机操作系统略有不同)。 - Xtra Coder
1
实际上它略大于1200 MB,可能高达3-3.5G。http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#gc_heap_32bit - ZZ 5
2
自从很久以前(至少5年)起,压缩oops一直是默认设置。此外,根据堆大小范围,有几种“模式”可以使用压缩oops,因此对于与32位相同大小的堆(约为2GB或更小),使用压缩oops几乎不需要付出太多成本(无需缩放,oops可以直接使用高位为零)。因此,64位接近于严格更好。 - BeeOnRope

5
正如您提到的,Java中的原始数字类型是定义良好的。
然而,如果您的Java应用程序使用本地代码库,那么选择32位或64位的JVM可能会有所区别,因为这些库可能是为32位应用程序、64位应用程序或两者都构建的。
如果您有支持仅32位应用程序的本地库,则需要使用32位JVM或构建库的64位版本。

1
作为一条经验法则,使用32位JRE进行开发,并在64位JRE上运行? - CoffeDeveloper

3

根据上下文,在本地开发中,我将始终使用64位JDK。主要是因为我可能需要整个内存空间进行构建和IDE。

话虽如此,对于生产环境的集成,我建议使用32位如果可能的话。为什么?

对于一些Java EE服务器,这些服务器已获得生产许可证,这将取决于某些因素,例如哪台机器有多少个核心等。对于WebSphere Liberty Profile而言,您还受到2GB的限制。

64位JRE会占用略多的内存,如果您试图将其限制在类似于2GB或更好的2x 1GB集群之类的东西中,则会有更多的灵活空间可以工作,而无需支付一分钱。

来自https://plumbr.eu/blog/java/should-i-use-32-or-64-bit-jvm

问题1:64位需要30-50%以上的堆空间。为什么?主要是由于64位架构中的内存布局。首先,64位JVM上对象头占用12个字节。其次,对象引用可以是4个或8个字节,具体取决于JVM标志和堆大小。与32位上8字节的头部和4字节的引用相比,这肯定增加了一些开销。您还可以深入我们早期的帖子中了解有关计算对象内存消耗的更多信息。
问题2:垃圾回收暂停时间更长。构建更大的堆意味着GC在清理未使用的对象时需要做更多的工作。在现实生活中,这意味着您必须特别谨慎地构建大于12-16GB的堆。如果没有精细调整和测量,您很容易引入跨越几分钟的完整GC暂停。在延迟不是至关重要且只能优化吞吐量的应用程序中,这可能是可以接受的,但在大多数情况下,这可能会成为一个阻碍。
为了减少 Java EE 环境的影响,可以将其中的一部分转移到其他微服务中,例如使用 ElasticSearch 进行搜索、使用 Hazelcast 进行缓存、使用数据库进行数据存储,并将 Java EE 服务器用于托管应用程序核心,而不是在其中运行服务。请注意保留 HTML 标签。

2
我认为有两个主要的差异需要考虑。一个已经在这里提到了,但另一个没有被提到。
一方面,正如其他人所提到的,是内存和数据类型。32位和64位JVM使用不同的本地数据类型大小和内存地址空间。
  • 64位JVM可以分配(可以使用)比32位更多的内存。
  • 64位使用具有更大容量的本机数据类型,但占用更多空间。因此,相同的对象也可能占用更多空间。
  • 对于垃圾收集器(GC)冻结机器的JVM,64位版本可能会更慢,因为GC必须检查更大的堆/对象,并且需要更长时间。
  • 有一个IBM演示文稿解释了这些差异。
另一方面,支持的本地库。使用JNI访问本地库的Java程序取决于JVM的类型而需要不同的版本。
  • 32位JVM使用32位本地库,64位JVM使用64位库。
  • 这意味着,如果您的程序使用依赖于本地代码的库(如SWT),则需要不同版本的库。请注意,在SWT下载页面中,有针对Linux/Windows 32位和64位的不同版本。请注意,有不同版本的Eclipse(每个版本都有不同版本的SWT)适用于32位和64位。
  • 一些应用程序,例如Alloy,包含32位本地库。它们在64位JVM上失败。您可以通过下载相应的64位本地库并适当地配置JNI来解决这些问题。

2
Oracle JVM 包括使用“压缩普通对象指针”的选项。基本上,JVM 可以使用 32 位值作为指向内存中对象的指针,而不是 64 位值。您可以检查 UseCompressedOops 标志。 - Jaime
1
不错。这个方法并不像x32那样高效,因为将所有指针限制在地址空间的低32位中,只需对它们进行零扩展即可使用。Java则会“解码”(左移3位并加到堆基址),增加些额外开销。但是,幸运的是,x86寻址模式可以实现“[基址+索引*8]”,因此对其进行解引用应该非常有效,并且只需要一个额外的指令来与非编码指针进行比较。当然,在编码时成本也会更高。总之,这看起来是Java的明智权衡,因为他们不想将堆限制在4GB以内。 - Peter Cordes
1
“本地数据类型”是什么意思?你是指像intlongchar等Java数据类型吗?还是指JVM内部的一些本地C++代码?后者大多数情况下都不相关,因为你的大部分内存使用通常都是Java堆的一部分,其数据类型的大小大多数情况下没有改变(关于引用有一个警告)。最重要的本地数据类型(实际上)可能也不会改变大小:如果你正在做很多非堆操作或者有本地代码,你可以选择保持数据类型相同的大小。 - BeeOnRope
1
此外,由于“压缩指针”是默认设置,对于任何堆大小可以进行直接比较的情况下,引用也将具有相同的大小。因此,64位基本上是严格更好的选择。当然,您可能会注意到,如果您需要大于32 GB的堆,则将使用64位引用,但是如果您需要如此大的堆,则32位已经无法考虑,因为它的最大堆大小约为2 GB。 - BeeOnRope
1
原始数据类型(如intlongchar)在两种类型的JVM中基本上工作相同。它们的大小不会改变。大小仅对引用发生更改。对这些类型的操作对于任何一个小于32位的原子操作。当数据大于32位时,在32位JVM中某些操作将不是原子操作。然而,这些差异可能是微不足道的。--差异主要出现在与本地库交互的对象或库中。--有关原始数据类型的大小,您可以查看https://dev59.com/P2kw5IYBdhLWcg3w_fiJ - Jaime
显示剩余2条评论

2

我需要了解32位JVM和64位JVM之间的区别吗?

如果您不是在构建性能关键的应用程序,那么您不必了解差异。32位JVM和64位JVM之间细微的差别对您的应用程序影响不大。您可以跳过后面的内容。

64位JVM比32位JVM表现更好吗?

大多数人认为64位比32位更大,因此64位JVM性能会比32位JVM性能更好。不幸的是,情况并非如此。64位JVM可能会比32位JVM具有轻微的性能下降。以下是Oracle JDK文档中有关64位JVM性能的摘录:

“通常,能够寻址更大内存量的好处是在64位VM与在32位VM上运行相同应用时存在一定的性能损失。

在SPARC上,将应用程序从32位VM转移到64位VM时,应用程序在64位平台上运行与在32位平台上运行相比性能差异大约为10-20%的降级。 在AMD64和EM64T平台上,这种差异取决于应用程序执行的指针访问量,范围从0-15%不等。”

32位JVM或64位JVM还有意义吗。

从32位JVM迁移到64位JVM时需要考虑哪些因素? a. GC暂停时间

从32位JVM迁移到64位JVM的主要原因是为了获得更大的堆大小(即-Xmx)。当增加堆大小时,自动会增加GC暂停时间,因为现在内存中有更多的垃圾需要清理。您需要在进行迁移之前进行适当的GC调整,否则您的应用程序可能会经历数秒钟到数分钟的暂停时间。

b. 本地库

如果您的应用程序使用Java Native Interface(JNI)访问本地库,则还需要升级本地库。因为32位JVM只能使用32位本地库。同样,64位JVM只能使用64位本地库。


x86 32位与64位是特殊的,因为64位模式有两倍于整数和FP寄存器供JIT编译器使用。对于其他ISA(如SPARC),情况并非如此:32位SPARC已经有足够的寄存器,所以只是更宽的指针,以及具有单个寄存器/单个指令的64位整数。因此,在x86之外,唯一的好处是使用64位整数的代码或需要超过4GB内存的代码。但在x86上,这是一个不那么明显的权衡,其中更大的指针仍然会影响性能(缓存占用/内存带宽),但更多的寄存器可以帮助实现更高效的代码。 - Peter Cordes
1
dup http://www.javaprogrammingforums.com/java-programming-tutorials/42036-subtle-differences-between-32-bit-jvm-64-bit-jvm.html - evandrix
@BhargavRao:从这个答案中删除特定工具(GCeasy)的提及有什么意义?这被标记为垃圾邮件/自我推广吗?您的更改没有编辑消息,看起来是一个明智的建议。 - Peter Cordes
@PeterCordes,你的猜测是正确的。我已经给发帖人发送了一条消息,他们可以在提供自我归属后进行编辑。 - Bhargav Rao

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接