内存中字节的大小-Java

内存中字节的大小-Java,java,performance,memory,Java,Performance,Memory,对于java程序中一个字节占用的内存量,我听到了各种不同的观点 我知道一个java字节中最多只能存储+127个字节,而且上面说一个字节只有8位,但我听说它实际上占用了与int相同的内存量,因此它只是一种有助于代码理解而不是效率的类型 有人能澄清这一点吗?这是一个特定于实现的问题吗?Java从来都不是特定于实现或平台的(至少就我们而言)。无论您在什么平台上,它们的基本类型都保证保持不变。这与(和被认为是C和C++的改进)不同,其中一些原始类型是平台特定的。 由于底层操作系统一次寻址四个(或八个,在

对于java程序中一个字节占用的内存量,我听到了各种不同的观点

我知道一个java字节中最多只能存储+127个字节,而且上面说一个字节只有8位,但我听说它实际上占用了与int相同的内存量,因此它只是一种有助于代码理解而不是效率的类型


有人能澄清这一点吗?这是一个特定于实现的问题吗?

Java从来都不是特定于实现或平台的(至少就我们而言)。无论您在什么平台上,它们的基本类型都保证保持不变。这与(和被认为是C和C++的改进)不同,其中一些原始类型是平台特定的。
由于底层操作系统一次寻址四个(或八个,在64位系统中)字节的速度更快,JVM可能会分配更多字节来存储基本字节,但您仍然只能在其中存储-128到127之间的值。

您被告知的完全正确。Java字节码规范只有4字节类型和8字节类型

字节、字符、int、short、boolean和float都存储在4个字节中

double和long存储在8个字节中


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

这取决于JVM如何应用填充等。字节数组(在任何健全的系统中)将被压缩到每个元素1个字节中,但是,一个具有四字节字段的类可以被紧密压缩,也可以填充到单词边界上——这取决于实现。

您可以始终使用long并将数据打包在自己的内存中以提高效率。然后,您可以始终使用所有4个字节。

一个很有启发性的练习是在一些代码上运行,这些代码使用字节和整数完成简单的操作。您将看到期望int参数在字节上运行的字节码,并且字节码被插入到一个字节到另一个字节


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

是的,Java中的字节变量实际上是内存中的4字节。但是,这对数组并不适用。一个20字节的字节数组的存储实际上在内存中只有20字节

这是因为Java字节码语言只知道两种整数类型:int和long。因此,它必须在内部将所有数字处理为任意一种类型,这些类型在内存中分别为4字节和8字节

但是,Java知道每种整数格式的数组。因此,短数组的存储实际上是每个条目两个字节,对于字节数组,每个条目一个字节


我一直说“的存储”的原因是,数组在Java中也是一个对象,每个对象本身都需要多个字节的存储,而不管实例变量需要什么存储,或者数组需要什么存储。

好的,有很多讨论,没有太多代码:)

这里有一个快速的基准。当涉及到这种事情时,它有正常的警告——测试内存由于抖动等原因会有异常,但是对于适当大的数字,它无论如何都是有用的。它有两种类型,每种类型有80个成员-LotsOfBytes有80个字节,LotsOfInts有80个int。我们构建了很多,确保它们不是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();
    }
}

因此,显然存在一些开销-从外观上看是8个字节,尽管LotsOfInts只需要7个字节(就像我说的,这里有一些奇怪的地方)-但关键是字节字段似乎是为LotsOfBytes打包的,因此需要(在开销移除后)只有LotsOfInts的四分之一内存。

字节=8bit=Java规范定义的一个字节

字节数组需要多少内存不是规范定义的,也不是复杂对象需要多少内存


对于Sun JVM,我记录了规则:

请参阅我的站点上的我的监视工具(www.csd.uoc.gr/~andreou)

X类{ 字节b1、b2、b3。。。; } long memoryUsed=MemoryMeasurer.measure(新的X()); (也可用于更复杂的对象/对象图)

在Sun的1.6JDK中,一个字节似乎确实需要一个字节(在旧版本中,内存是int~byte)。但请注意,即使在旧版本中,字节[]也被压缩为每个条目一个字节


不管怎样,关键是不需要像上面Jon Skeet那样只给出估计的复杂测试。我们可以直接测量物体的大小

通过阅读上述评论,我的结论似乎会让很多人感到惊讶(我也感到惊讶),因此值得重复:

  • 变量的旧大小(int)=大小(字节)不再适用,至少在Sun的Java6中是这样

相反,size(byte)=1 byte(!!)

答案可能取决于您的JVM版本,也可能取决于您运行的CPU体系结构。Intel系列CPU有效地执行字节操作(由于其8位CPU历史)。一些RISC芯片在许多操作中需要字(4字节)对齐。堆栈上的变量、类中的字段和数组中的内存分配可能不同。

只是想指出

一个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
我用电脑做了一个测试 请注意,我使用的是64位Oracle/Sun Java 6,没有任何引用压缩等

每个对象都占用一些空间,另外JVM需要知道 class X { byte b1, b2, b3...; } long memoryUsed = MemoryMeasurer.measure(new X());
byte B=(byte)200;//B contains 200
System.out.println((B+256)%256);//Prints 200
System.out.println(B&0xFF);//Prints 200
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