内存中一个字节的大小 – Java

我听说了一个字节在一个Java程序中占用的内存量的不同意见。

我知道你可以在java字节中存储不超过+127, 文档说一个字节只有8位,但在这里我被告知它实际上占用与int相同数量的内存,因此只是一种有助于代码理解而不是效率的types。

任何人都可以清除这个,这是一个具体的实现问题?

好的,有很多的讨论,而不是很多的代码:)

这是一个快速的基准。 当涉及到这种事情时,它有一个正常的警告 – 由于JITting等原因,testing内存有一些奇怪的地方,但是适当的大数目是有用的。 它有两种types,每种有80个成员 – LotsOfBytes有80个字节,LotsOfInts有80个成员。 我们build立了很多,确保它们不是GC'd,并检查内存使用情况:

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的四分之一内存。

是的,一个字节variables实际上是4个字节的内存。 但是这不适用于数组。 一个20字节的字节数组实际上只有20个字节的内存。 这是因为Java字节码语言只知道整数和长整型为数字types(所以它必须处理所有的数字都是4字节或8字节的任何一种),但它知道每一个可能的数字大小的数组(所以短arrays在事实上每个条目的两个字节和字节数组实际上是每个条目的一个字节)。

Java从来没有实现或平台特定(至less就原始types大小而言)。 无论你在哪个平台上,它们的原始types总是保证不变。 这不同于C和C ++(并被认为是一种改进),其中一些基本types是特定于平台的。

由于底层操作系统一次处理四个(或八个,64位系统)字节的速度更快,JVM可能会分配更多的字节来存储原始字节,但是您仍然只能将-128 127在里面。

一个透露的练习是在一些代码上运行javap ,用字节和整数进行简单的事情。 你会看到字节码,它们需要int参数在字节上运行,而字节码被插入到彼此之间。

请注意,虽然字节数组不是以4字节值的数组forms存储的,所以1024长度的字节数组将使用1k的内存(忽略任何开销)。

我使用http://code.google.com/p/memory-measurer/进行了testing。请注意,我使用的是64位Oracle / Sun Java 6,没有任何引用压缩等。

每个对象占用一些空间,加上JVM需要知道该对象的地址,“地址”本身是8个字节。

对于原语,看起来像基元被转换为64位,以获得更好的性能(当然!):

 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 

PS Oracle Java 6,最新最好的,64位,1.6.0_37,MacOS X

这取决于JVM如何应用填充等等。字节数组(将在任何合理的系统中)被打包成每字节1字节,但是具有4字节字段的类可以被紧密打包或填充到字边界上 – 它依赖于实现。

你被告知是完全正确的。 Java字节码规范只有4字节types和8字节types。

字节,char,int,short,boolean,float都以4个字节存储。

double和long存储在8个字节中。

然而字节码只是故事的一半。 还有JVM,这是特定于实现的。 Java字节代码中有足够的信息来确定一个variables被声明为一个字节。 JVM实现者可能决定只使用一个字节,尽pipe我认为这是不太可能的。

你总是可以使用longs和自己的数据打包来提高效率。 那么你总是可以保证你将使用全部4个字节。

字节= 8位=由Java Spec定义的一个字节。

一个字节数组需要多less内存不是 Spec定义的,也没有定义一个复杂对象需要多less。

对于Sun JVM,我logging了以下规则: https : //www.sdn.sap.com/irj/sdn/weblogs?blog=/ pub/wlg/ 5163

在我的网站上查看我的MonitoringTools(www.csd.uoc.gr/~andreou)

 class X {
   字节b1,b2,b3 ...;
 }

 long memoryUsed = MemoryMeasurer.measure(new X());

(它也可以用于更复杂的对象/对象图)

在Sun的1.6 JDK中,似乎一个字节确实需要一个字节(在旧版本中,int〜字节在内存方面)。 但请注意,即使在较旧的版本中,byte []也打包为每个条目一个字节。

无论如何,重要的是,没有必要像Jon Skeet的上述那样进行复杂的testing,只给出估计。 我们可以直接测量一个对象的大小!

通过以上的评论,我的结论似乎会让很多人感到吃惊(这也是一个惊喜),所以值得重复的是:

  • 旧的大小(int)==大小(字节)的variables保持不了 ,至less在Sun的Java 6中。

相反,大小(字节)== 1字节(!!)

只是想指出这个说法

您可以在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 

看来答案很可能取决于您的JVM版本,也可能取决于您运行的CPU架构。 英特尔的CPU系列有效地进行字节操作(由于其8位CPU历史logging)。 一些RISC芯片需要字(4字节)alignment许多操作。 内存分配对于堆栈中的variables,类中的字段和数组中的内容可以不同。