为什么未定义Java的布尔原始大小?


111

Java虚拟机规范说有布尔有限的支持原始类型。

没有Java虚拟机指令专门用于布尔值的操作。相反,将对布尔值进行操作的Java编程语言中的表达式编译为使用Java虚拟机int数据类型的值。

以上暗示(尽管我可能会误解了)在对布尔值进行操作时使用了int数据类型,但这是一个32位内存构造。假设布尔值仅表示1位信息:

  • 为什么不将字节(或简称)类型用作布尔值而不是int的代理?
  • 对于任何给定的JVM,最确切地找出用于存储布尔类型的内存量的最可靠方法是什么?

Answers:


116

简短的答案:是的,布尔值作为32位实体进行操作,但布尔数组每个元素使用1个字节。

更长的答案:JVM使用32位堆栈单元,用于保存局部变量,方法参数和表达式值。小于1个单元的基元被填充,大于32位(长和双精度)的基元占用2个单元。该技术可最大程度地减少操作码的数量,但确实有一些特殊的副作用(例如需要屏蔽字节)。

数组中存储的基元可能使用少于32位,并且有不同的操作码来加载和存储数组中的基元值。布尔值和字节值都使用baloadbastore操作码,这意味着布尔数组每个元素占用1个字节。

就内存中对象布局而言,这在“私有实现” 规则下已涉及到,它可以是1位,1字节,或者如另一个提示所指出的,与64位双字边界对齐。最有可能的是,它占用基础硬件的基本字长(32或64位)。


尽量减少布尔值使用的空间:对于大多数应用程序来说,这实际上不是问题。堆栈框架(包含局部变量和方法参数)不是很大,并且在大型方案中,对象中的离散布尔也不大。如果您有很多带有布尔值的对象,则可以使用通过getter和setter管理的位字段。但是,您将付出的CPU时间损失可能大于内存中的损失。


对于布尔/字节类成员,是否也是4个字节,这是否也是正确的?类实例是在堆栈上整体分配的,因此我可以想象,JVM可能应该为每个布尔/字节成员使用1个字节,最后对整个类实例进行4个字节的对齐。是这样吗?(如果您有引用证明,请分享)
dma_k 2010年

@dma_k:如我的回复所述,类实例的布局取决于实现。但是,请注意,类实例未存储在堆栈中,而是存储在堆中(尽管您会看到对JDK 7“转义分析”的一些引用,这些对象将对象从堆栈移动到堆中,但情况并非如此;见java.sun.com/javase/7/docs/technotes/guides/vm/...)
kdgregory

1
有时包装布尔值实际上可能更快。每当缓存大小重要时,最好打包。例如,分段主筛以32 kB(L1缓存大小)的块工作,比未分段的筛快得多。块之间有一些开销,打包时开销减少了八倍。我还没有测量。
maaartinus

7

继承层次结构中某个地方的单个布尔值最多可以使用8个字节!这是由于填充。在Java对象使用多少内存中可以找到更多详细信息

回到布尔消耗多少的问题,是的,它确实消耗了至少一个字节,但是由于对齐规则,它可能消耗更多。恕我直言,更有趣的是知道boolean []每个条目将消耗一个字节而不是一位,并且由于对齐和数组的size字段而导致一些开销。在图算法中,大位字段很有用,并且需要注意的是,如果使用boolean [],则需要的内存几乎比实际需要的内存多8倍(1字节对1位)。


无论如何将如何使用boolean []?
Thomas Jung,

boolean []可用于蒙版。有时,BitSet可能会更好,因为它具有一些有用的方法。
Michael Munsey 2010年

5

第五章Java in a Nutshell(O'Reilly)说布尔类型为1个字节。根据对堆的检查显示,这可能是错误的。我想知道大多数JVM是否在分配小于一个字节的变量方面遇到问题。


3

布尔映射是在考虑32位CPU的情况下完成的。int值具有32位,因此可以一次操作进行处理。

这是Peter Norvig的Java IAQ的一种解决方案:不常见问题,用于测量大小(有些不精确):

static Runtime runtime = Runtime.getRuntime();
...
long start, end;
Object obj;
runtime.gc();
start = runtime.freememory();
obj = new Object(); // Or whatever you want to look at
end =  runtime.freememory();
System.out.println("That took " + (start-end) + " bytes.");

由于此对话是关于基元的,因此您必须在测试方面很有创造力,因为除非基元是实例或数组上的字段,否则它们不会存储在堆中。而且这些都没有回答Java将如何选择将其存储在堆栈中的问题。
杰西

2

CPU在特定的数据类型长度上运行。对于32位CPU,它们的长度为32位,因此在Java中称为“ int”。低于或高于此的所有内容都必须填充或分割为该长度,然后CPU才能对其进行处理。这并不需要花费很多时间,但是如果您需要2个CPU周期而不是1个基本操作,则意味着成本/时间将增加一倍。

该规范专用于32位CPU,因此它们可以使用其本机数据类型处理布尔值。

您只能在此处设置一个:速度或内存-SUN决定速度。


1

Sun Java教程说,布尔值代表一小部分信息,但是它的“大小”不是精确定义的。布尔文字只有两个可能的值,即true和false。有关详细信息,请参见Java数据类型


-10

为什么不制作一个这样的.java文件:

空.java

class Empty{
}

像这样的一类:

NotEmpty.java

class NotEmpty{
   boolean b;
}

将它们都编译,然后用十六进制编辑器比较.class文件。


5
这是另一个指标,与内存中原始布尔类型的大小无关。
乔尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.