为什么java中BitSet的内部数据存储为long[]而不是Java中的int[]?

Why is the internal data of BitSet in java stored as long[] instead of int[] in Java?

在java中,BitSet的内部数据存储为long[]而不是int[],我想知道为什么?这是 jdk 中的代码:

 /**
 * The internal field corresponding to the serialField "bits".
 */
 private long[] words;

如果都是为了性能,我想知道为什么长[]存储会获得更好的性能。

肯定是一个优化问题:单个long值最多存储64位,而int仅32位。因此,任何64位以下的用户长度只需要一个条目 在数组中。如果它是 int 的数组,它将需要 两个条目 ,维护起来更慢且更重。

在 64 位机器上,对单个 long 值执行按位运算的性能明显高于对两个 int 值执行相同操作的性能,因为硬件直接支持 64 位值。在 32 位机器上,差异可能不是很大。

我可能是错的,但是使用 long[] 时 bitSet 的基数比使用 int[] 时大得多。因为数组的最大大小对于它们两者来说非常相似(但限于堆大小)。

基于对来源的粗略阅读 here。看起来,主要原因纯粹是为了表现。这是从源中检索到的评论。

BitSets are packed into arrays of "words." Currently a word is a long, which consists of 64 bits, requiring 6 address bits. The choice of word size is determined purely by performance concerns.

查询或操作单个位时,没有显着差异。您必须计算单词索引并读取该单词,并且在更新的情况下,操作该单词的一位并将其写回。 int[]long[] 都是一样的。

有人可能会争辩说,如果您有真正的 32 位内存总线,使用 long 而不是 int 可能会增加必须为单个位操作传输的内存量, 但由于 Java 是上个世纪九十年代设计的,所以设计师认为这不再是问题。

另一方面,一次处理 多个 位时你会大获全胜。当您对整个 BitSet 执行 and, or or xor 等操作时,您可以在使用 long 数组时一次对整个字执行操作,读取 64 位。

类似地,当searching for the next set bit时,如果该位不在起始位置的字内,则随后的字首先进行零测试,这是一个内在的操作,即使对于大多数32位CPUs,所以你可以一次跳过64个零位,而第一个非零字肯定会包含下一个设置位,所以整个迭代只需要一个位提取操作。

批量操作的这些好处将超过任何与单位相关的缺点,如果有的话。如前所述,今天的大多数 CPU 都能够直接对 64 位字进行所有操作。