内存中一个字节的大小 - Java
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/229886/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Size of a byte in memory - Java
提问by Ben Page
I have heard mixed opinions over the amount of memory that a byte takes up in a java program.
对于一个字节在 Java 程序中占用的内存量,我听到了不同的意见。
I am aware you can store no more than +127 in a java byte, and the documentationsays that a byte is only 8 bits but hereI am told that it actually takes up the same amount of memory as an int, and therefore is just a Type that helps in code comprehension and not efficiency.
我知道你可以在一个 java 字节中存储不超过 +127,并且文档说一个字节只有 8 位,但在这里我被告知它实际上占用了与 int 相同的内存量,因此只是一种有助于代码理解而不是效率的类型。
Can anyone clear this up, and would this be an implementation specific issue?
任何人都可以解决这个问题,这会是一个特定于实现的问题吗?
采纳答案by Jon Skeet
Okay, there's been a lot of discussion and not a lot of code :)
好的,有很多讨论,而不是很多代码:)
Here's a quick benchmark. It's got the normal caveats when it comes to this kind of thing - testing memory has oddities due to JITting etc, but with suitably large numbers it's useful anyway. It has two types, each with 80 members - LotsOfBytes has 80 bytes, LotsOfInts has 80 ints. We build lots of them, make sure they're not GC'd, and check memory usage:
这是一个快速基准。当涉及到这种事情时,它有正常的警告 - 由于 JITting 等原因,测试内存有一些奇怪的地方,但是如果有足够大的数字,它无论如何都是有用的。它有两种类型,每种类型有 80 个成员——LotsOfBytes 有 80 个字节,LotsOfInts 有 80 个整数。我们构建了很多,确保它们不是 GC,并检查内存使用情况:
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();
}
}
Output on my box:
我的盒子上的输出:
Size for LotsOfBytes: 88811688
Average size: 88.811688
Size for LotsOfInts: 327076360
Average size: 327.07636
0
So obviously there's some overhead - 8 bytes by the looks of it, although somehow only 7 for LotsOfInts (? like I said, there are oddities here) - but the point is that the byte fields appear to be packed in for LotsOfBytes such that it takes (after overhead removal) only a quarter as much memory as LotsOfInts.
所以很明显有一些开销 - 从它的外观来看是 8 个字节,但不知何故,LotsOfInts 只有 7 个字节(?就像我说的,这里有一些奇怪的地方) - 但关键是字节字段似乎是为 lotofBytes 打包的,这样它仅占用(去除开销后)内存为lotsOfInts 的四分之一。
回答by Bill the Lizard
Java is never implementation or platform specific (at least as far as primitive type sizesare concerned). They primitive types are always guaranteed to stay the same no matter what platform you're on. This differs from (and was considered an improvement on) C and C++, where some of the primitive types were platform specific.
Java 从不特定于实现或平台(至少就原始类型大小而言)。无论您在哪个平台上,它们的原始类型始终保证保持不变。这不同于(并且被认为是对 C 和 C++ 的改进),其中一些原始类型是特定于平台的。
Since it's faster for the underlying operating system to address four (or eight, in a 64-bit system) bytes at a time, the JVM may allocate more bytes to store a primitive byte, but you can still only store values from -128 to 127 in it.
由于底层操作系统一次处理四个(或八个,在 64 位系统中)字节更快,JVM 可能会分配更多字节来存储原始字节,但您仍然只能存储从 -128 到其中 127 个。
回答by Steve McLeod
What you've been told is exactly right. The Java byte code specification only has 4-byte types and 8-byte types.
你被告知的是完全正确的。Java 字节码规范只有 4 字节类型和 8 字节类型。
byte, char, int, short, boolean, float are all stored in 4 bytes each.
byte、char、int、short、boolean、float 均以 4 个字节存储。
double and long are stored in 8 bytes.
double 和 long 以 8 个字节存储。
However byte code is only half the story. There's also the JVM, which is implementation-specific. There's enough info in Java byte code to determine that a variable was declared as a byte. A JVM implementor maydecide to use only a byte, although I think that is highly unlikely.
然而,字节码只是故事的一半。还有 JVM,它是特定于实现的。Java 字节码中有足够的信息来确定变量是否被声明为字节。JVM 实现者可能决定只使用一个字节,尽管我认为这是极不可能的。
回答by Jon Skeet
It depends on how the JVM applies padding etc. An array of bytes will (in any sane system) be packed into 1-byte-per-element, but a class with four byte fields could either be tightly packed or padded onto word boundaries - it's implementation dependent.
这取决于 JVM 如何应用填充等。字节数组将(在任何健全的系统中)打包为每个元素 1 个字节,但具有四个字节字段的类可以紧密打包或填充到字边界上 -它依赖于实现。
回答by Christopher Lightfoot
You could always use longs and pack the data in yourself to increase efficiency. Then you can always gaurentee you'll be using all 4 bytes.
你总是可以使用 longs 并自己打包数据以提高效率。然后你总是可以保证你将使用所有 4 个字节。
回答by izb
A revealing exercise is to run javapon some code that does simple things with bytes and ints. You'll see bytecodes that expect int parameters operating on bytes, and bytecodes being inserted to co-erce from one to another.
一个启发性的练习是在一些使用字节和整数做简单事情的代码上运行javap。您将看到期望 int 参数对字节进行操作的字节码,以及被插入以强制从一个到另一个的字节码。
Note though that arrays of bytes are not stored as arrays of 4-byte values, so a 1024-length byte array will use 1k of memory (Ignoring any overheads).
请注意,尽管字节数组不存储为 4 字节值的数组,因此 1024 长度的字节数组将使用 1k 内存(忽略任何开销)。
回答by Mecki
Yes, a byte variable in Java is in fact 4 bytes in memory. However this doesn't hold true for arrays. The storage of a byte array of 20 bytes is in fact only 20 bytes in memory.
是的,Java 中的字节变量实际上是内存中的 4 个字节。然而,这不适用于数组。20个字节的字节数组的存储实际上在内存中只有20个字节。
That is because the Java Bytecode Language only knows two integer number types: ints and longs. So it must handle all numbers internally as either type and these types are 4 and 8 bytes in memory.
这是因为 Java 字节码语言只知道两种整数类型:int 和 long。因此它必须在内部将所有数字作为任一类型处理,这些类型在内存中分别为 4 和 8 个字节。
However, Java knows arrays with every integer number format. So the storage of short arrays is in fact two bytes per entry and one byte per entry for byte arrays.
然而,Java 知道所有整数格式的数组。因此,对于字节数组,短数组的存储实际上是每个条目两个字节,每个条目一个字节。
The reason why I keep saying "the storage of" is that an array is also an object in Java and every object requires multiple bytes of storage on its own, regardless of the storage that instance variables or the array storage in case of arrays require.
我一直说“的存储”的原因是数组在 Java 中也是一个对象,并且每个对象本身都需要多个字节的存储,而不管实例变量的存储或数组需要的数组存储。
回答by kohlerm
byte = 8bit = one byte defined by the Java Spec.
byte = 8bit = Java 规范定义的一个字节。
how much memory an byte array needs is notdefined by the Spec, nor is defined how much a complex objects needs.
规范没有定义字节数组需要多少内存,也没有定义复杂对象需要多少内存。
For the Sun JVM I documented the rules: https://www.sdn.sap.com/irj/sdn/weblogs?blog=/pub/wlg/5163
对于 Sun JVM,我记录了规则:https: //www.sdn.sap.com/irj/sdn/weblogs?blog=/pub/wlg/ 5163
回答by kohlerm
See my MonitoringTools at my site (www.csd.uoc.gr/~andreou)
在我的站点 (www.csd.uoc.gr/~andreou) 上查看我的 MonitoringTools
class X { byte b1, b2, b3...; } long memoryUsed = MemoryMeasurer.measure(new X());
(It can be used for more complex objects/object graphs too)
(它也可以用于更复杂的对象/对象图)
In Sun's 1.6 JDK, it seems that a byte indeed takes a single byte (in older versions, int ~ byte in terms of memory). But note that even in older versions, byte[] were also packed to one byte per entry.
在 Sun 的 1.6 JDK 中,似乎一个字节确实需要一个字节(在旧版本中,就内存而言, int ~ 字节)。但请注意,即使在旧版本中,byte[] 也被打包为每个条目一个字节。
Anyway, the point is that there is no need for complex tests like Jon Skeet's above, that only give estimations. We can directly measure the size of an object!
无论如何,关键是不需要像上面的 Jon Skeet 那样复杂的测试,只给出估计。我们可以直接测量物体的大小!
回答by kohlerm
Reading through the above comments, it seems that my conclusion will come as a surprise to many (it is also a surprise to me), so it worths repeating:
看了上面的评论,似乎我的结论会出乎很多人的意料(对我来说也是一个惊喜),所以值得重复一遍:
- The old size(int) == size(byte) for variables holds no more, at least in Sun's Java 6.
- 变量的旧 size(int) == size(byte) 不再包含,至少在 Sun 的 Java 6 中是这样。
Instead, size(byte) == 1 byte (!!)
相反,size(byte) == 1 byte (!!)