好的,有很多讨论但是代码很少 :)
这里是一个快速的基准测试。在这种情况下,测试内存存在奇怪的问题,因为JIT等原因,但是对于足够大的数字,它仍然很有用。它有两种类型,每种类型都有80个成员 - LotsOfBytes有80个字节,LotsOfInts有80个整数。我们建立了许多这样的对象,确保它们不会被垃圾回收,并检查内存使用情况:
class LotsOfBytes
{
byte a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af;
byte b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf;
byte c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf;
byte d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, da, db, dc, dd, de, df;
byte e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, ea, eb, ec, ed, ee, ef;
}
class LotsOfInts
{
int a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af;
int b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf;
int c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf;
int d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, da, db, dc, dd, de, df;
int e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, ea, eb, ec, ed, ee, ef;
}
public class Test
{
private static final int SIZE = 1000000;
public static void main(String[] args) throws Exception
{
LotsOfBytes[] first = new LotsOfBytes[SIZE];
LotsOfInts[] second = new LotsOfInts[SIZE];
System.gc();
long startMem = getMemory();
for (int i=0; i < SIZE; i++)
{
first[i] = new LotsOfBytes();
}
System.gc();
long endMem = getMemory();
System.out.println ("Size for LotsOfBytes: " + (endMem-startMem));
System.out.println ("Average size: " + ((endMem-startMem) / ((double)SIZE)));
System.gc();
startMem = getMemory();
for (int i=0; i < SIZE; i++)
{
second[i] = new LotsOfInts();
}
System.gc();
endMem = getMemory();
System.out.println ("Size for LotsOfInts: " + (endMem-startMem));
System.out.println ("Average size: " + ((endMem-startMem) / ((double)SIZE)));
// Make sure nothing gets collected
long total = 0;
for (int i=0; i < SIZE; i++)
{
total += first[i].a0 + second[i].a0;
}
System.out.println(total);
}
private static long getMemory()
{
Runtime runtime = Runtime.getRuntime();
return runtime.totalMemory() - runtime.freeMemory();
}
}
我的电脑上的输出:
Size for LotsOfBytes: 88811688
Average size: 88.811688
Size for LotsOfInts: 327076360
Average size: 327.07636
0
显然这里有一些开销 - 看起来是8个字节,尽管对于LotsOfInts只有7个(?像我之前说的,这里有一些奇怪的地方)- 但关键是这些字节字段似乎被紧密打包到了LotsOfBytes中,经过去除开销后,它所占用的内存只有LotsOfInts的四分之一。
class LotsOfBytes { byte a0; } class LotsOfInts { int a0; }
将没有任何显着差异。 - Ivan BalashovLotsOfBytes
的大小为 -914712,平均大小为 -914.712。LotsOfInts
的大小为 336000,平均大小为 336.0。0。 - Bitterblue是的,在Java中,byte变量实际上占据了4个字节的内存。然而,对于数组来说并非如此。一个长度为20个字节的byte数组实际上只在内存中占据了20个字节的空间。
这是因为Java字节码语言只知道两种整数类型:int和long。因此,它必须将所有数字在内部处理为这两种类型,这两种类型在内存中分别占据4个字节和8个字节。
但是,Java可以使用每种整数数字格式的数组。因此,short数组的存储实际上是每个元素占用两个字节,byte数组的存储实际上是每个元素占用一个字节。
我一直强调“存储”,是因为在Java中,数组也是一个对象,每个对象都需要自己的多个字节的存储空间,无论实例变量还是数组存储所需的存储空间。
int[]
数组大小的更加精确的公式?它会是4[=length] + 4[=int_size]*length(array) + 8_byte_align
吗? - dma_kJava在实现或平台方面从来不是特定的(至少就原始类型大小而言)。无论您在哪个平台上,它们的原始类型始终保持相同。这与C和C ++有所不同(并被认为是一种改进),其中一些原始类型是特定于平台的。
由于底层操作系统以每次处理四个字节(在64位系统中为八个字节)的速度更快,因此JVM可能会分配更多字节来存储原始字节,但您仍然只能在其中存储-128到127的值。
byte: 16 bytes,
int: 16 bytes,
long: 24 bytes.
byte[1]: 24 bytes
int[1]: 24 bytes
long[1]: 24 bytes
byte[2]: 24 bytes
int[2]: 24 bytes
long[2]: 32 bytes
byte[4]: 24 bytes
int[4]: 32 bytes
long[4]: 48 bytes
byte[8]: 24 bytes => 8 bytes, "start" address, "end" address => 8 + 8 + 8 bytes
int[8]: 48 bytes => 8 integers (4 bytes each), "start" address, "end" address => 8*4 + 8 + 8 bytes
long[8]: 80 bytes => 8 longs (8 bytes each), "start" address, "end" address => 8x8 + 8 + 8 bytes
现在猜猜看...
byte[8]: 24 bytes
byte[1][8]: 48 bytes
byte[64]: 80 bytes
byte[8][8]: 240 bytes
P.S. Oracle Java 6,最新版本,64位,1.6.0_37,MacOS X
这取决于JVM如何应用填充等技术。在任何理智的系统中,字节数组将被打包成每个元素1字节,但具有四个字节字段的类可以紧密地打包或填充到字边界上 - 这取决于实现。
您可以始终使用长整型并自行打包数据以增加效率。这样,您就可以保证始终使用所有4个字节。
一个byte等于8个bit,在Java规范中有定义。
然而,一个byte数组需要多少内存以及复杂对象需要多少内存并没有被规范所定义。
对于Sun JVM,我记录了以下规则:https://www.sdn.sap.com/irj/sdn/weblogs?blog=/pub/wlg/5163
想要指出的是,这个语句
在Java字节中,你最多只能存储+127
并不完全正确。
你总是可以在一个字节中存储256个不同的值,因此你可以轻松地将0..255范围内的值视为“无符号”字节。
这完全取决于如何处理这8位。
例子:
byte B=(byte)200;//B contains 200
System.out.println((B+256)%256);//Prints 200
System.out.println(B&0xFF);//Prints 200