在内存和CPU使用方面,哪种更有效率——布尔数组还是位集?仅使用get/set/clear方法(对于数组分别为==、=、Arrays.fill)并不使用特定的位集方法。
在内存和CPU使用方面,哪种更有效率——布尔数组还是位集?仅使用get/set/clear方法(对于数组分别为==、=、Arrays.fill)并不使用特定的位集方法。
Boolean[]
每个布尔值使用约4-20字节。boolean[]
每个布尔值使用约1字节。BitSet
每个布尔值使用约1位。如果内存大小不是问题,那么使用boolean[]可能更简单。
通过在Sun JDK 1.6上使用筛法计算素数的一些基准测试(进行10次迭代来热身,给JIT编译器一个机会并排除随机调度延迟,Core 2 Duo T5600 1.83GHz):
对于非常小的大小,BitSet比boolean[]更节省内存。数组中的每个布尔值占用一个字节。对于BitSet,从runtime.freeMemory()得到的数字有点混乱,但比boolean[]要少。
对于非常大的大小,boolean[]比较CPU高效,但它们在很大程度上是相当的。例如,对于100万个元素,boolean[]比BitSet快四倍左右(例如6毫秒比27毫秒),而对于一千万和一亿,它们则基本相同。
BitSet
,因为它表达了意图,除非我有许多相对较小的位集运行并需要优化运行时间。 - starblueboolean[]
和 BitSet
在 CPU 效率上大致相同吗?感觉 boolean[]
应该更高效。 - Utkuboolean []
更快的最大大小,这个大小可以合理地适应缓存。 - starblue这里您可以看到一个内存/时间基准测试,比较了一个boolean[][]三角形矩阵和BitSet[]三角形矩阵。
我创建、设置和读取(size * (size-1) / 2)个值,并比较内存使用和时间...
希望这有所帮助...
这里是代码...(只是快速脏代码测试,抱歉 ;)
import java.util.BitSet;
import java.util.Date;
public class BooleanBitSetProfiler {
Runtime runtime;
int sum = 0;
public void doIt() {
runtime = Runtime.getRuntime();
long[][] bitsetMatrix = new long[30][2];
long[][] booleanMatrix = new long[30][2];
int size = 1000;
for (int i = 0; i < booleanMatrix.length; i++) {
booleanMatrix[i] = testBooleanMatrix(size);
bitsetMatrix[i] = testBitSet(size);
size += 2000;
}
int debug = 1;
for (int j = 0; j < booleanMatrix.length; j++){
System.out.print(booleanMatrix[j][0] + ";");
}
System.out.println();
for (int j = 0; j < booleanMatrix.length; j++){
System.out.print(booleanMatrix[j][1] + ";");
}
System.out.println();
for (int j = 0; j < bitsetMatrix.length; j++){
System.out.print(bitsetMatrix[j][0] + ";");
}
System.out.println();
for (int j = 0; j < bitsetMatrix.length; j++){
System.out.print(bitsetMatrix[j][1] + ";");
}
System.out.println();
}
private long memory () {
return runtime.totalMemory() - runtime.freeMemory();
}
private long[] testBooleanMatrix(int size) {
runtime.gc();
long startTime = new Date().getTime();
long startMemory = memory();
boolean[][] matrix = new boolean[size][];
for (int i = 0; i < size; i++) {
matrix[i] = new boolean[size - i - 1];
}
long creationMemory = memory();
long creationTime = new Date().getTime();
for (int i = 0; i < size; i++) {
for (int j = 0; j < matrix[i].length; j++) {
matrix[i][j] = i % 2 == 0;
}
}
long setMemory = memory();
long setTime = new Date().getTime();
for (int i = 0; i < size; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (matrix[i][j]) sum++;
}
}
long readTime = new Date().getTime();
System.out.println("Boolean[][] (size " + size + ")");
System.out.println("Creation memory " + printMem(creationMemory-startMemory) + ", set memory " + printMem(setMemory-startMemory));
System.out.println("Creation time " + printTime(creationTime-startTime) + ", set time " + printTime(setTime - creationTime) + " read time " + printTime(readTime - setTime) + "\n");
runtime.gc();
return new long[]{(setMemory-startMemory)/(1024*1024), (readTime-startTime)};
}
private long[] testBitSet(int size) {
runtime.gc();
long startTime = new Date().getTime();
long startMemory = memory();
BitSet[] matrix = new BitSet[size];
for (int i = 0; i < size; i++) {
matrix[i] = new BitSet(size - i - 1);
}
long creationMemory = memory();
long creationTime = new Date().getTime();
for (int i = 0; i < size; i++) {
for (int j = 0; j < matrix[i].size(); j++) {
matrix[i].set(j, (i % 2 == 0));
}
}
long setMemory = memory();
long setTime = new Date().getTime();
for (int i = 0; i < size; i++) {
for (int j = 0; j < matrix[i].size(); j++) {
if (matrix[i].get(j)) sum++;
}
}
long readTime = new Date().getTime();
System.out.println("BitSet[] (size " + size + ")");
System.out.println("Creation memory " + printMem(creationMemory-startMemory) + ", set memory " + printMem(setMemory-startMemory));
System.out.println("Creation time " + printTime(creationTime-startTime) + ", set time " + printTime(setTime - creationTime) + " read time " + printTime(readTime - setTime) + "\n");
runtime.gc();
return new long[]{(setMemory-startMemory)/(1024*1024), (readTime-startTime)};
}
private String printMem(long mem) {
mem = mem / (1024*1024);
return mem + "MB";
}
private String printTime(long milis) {
int seconds = (int) (milis / 1000);
milis = milis % 1000;
return seconds > 0 ? seconds + "s " + milis + "ms" : milis + "ms";
}
}
BitSet
的文档已经非常明确了。具体来说:
The internal field corresponding to the serialField "bits".
89
90 private long[] words;
虽然有些超出你的问题范围,但如果存储是一个问题,你可能需要了解Huffman compression。例如,00000001
可以通过频率压缩成等价于{(7)0, (1)1}
。一个更“随机”的字符串00111010
将需要更复杂的表示方式,例如{(2)0, (3)1, (1)0, (1)1, (1)0}
,并且占用更多空间。根据您的位数据结构,您可能会从使用它获得一些存储优势,超出BitSet
。
这取决于具体情况。BitSet更节省内存,但如果需要多线程访问,boolean[]可能是更好的选择。例如,对于计算质数,您只需将布尔值设置为true,因此不需要同步。 Hans Boehm 写了一些关于此的论文,相同的技术也可以用于标记图中的节点。
从Java到CPU是完全基于虚拟机的。例如,布尔值过去实际上是作为32位值实现的(很可能到今天仍然如此)。
除非你知道它很重要,否则最好编写清晰的代码、分析性能,然后修复那些运行缓慢或消耗大量内存的部分。
你可以边做边改进。例如,我曾经决定不在字符串上调用.intern(),因为当我在分析器中运行代码时,它会使其变慢(尽管使用的内存更少)。
我相信BitSet更加节省内存和CPU,因为它可以将位数据内部打包成int、long或本地数据类型,而boolean[]则需要一个字节来存储每个位数据。此外,如果您使用其他方法(如and、or等),您会发现BitSet更加高效,因为不需要迭代数组的每个元素;而是使用位运算。
Boolean[]
每个值使用4或8个字节,但绝对不会超过20个字节。如果假设应用程序为每个元素创建一个新的Boolean
对象(尽管没有理由这样假设),那么大多数实现将需要24个字节用于对象,加上4或8个字节的引用,总共最多32个字节。但在实际应用中,谁会这样做呢... - undefinedboolean[]
的情况下,是否有意义假设一个理智的人会使用Boolean[]
数组。无论如何,短语“每个布尔值使用约4-20字节”是误导性的。 - undefined