龙珠

修炼自己与发现世界

Java:8种基本数据类型及其所占内存字节数

内存中最基本的是二进制位,也就是比特(bit)。一个基本的数据单位是字节(byte),1byte = 8bit。注意:字节是内存最小寻址单位!

Java中有8种基本的数据类型,分别是:

逻辑:boolean;

整数:byte、short、int、long;

字符:char;

浮点:float、double。

八种数据类型所占用的内存大小(字节)分别为:

逻辑:boolean;

整数:byte-1、short-2、int-4、long-8;

字符:char-2;

浮点:float-4、double-8。

咦,可以看出来,只有boolean是没有说明的。那boolean是有多大呢?

查了一下,貌似这个问题还是个坑。在java中的 boolean 在内存中占多少字节?中讨论跟帖了好多。

boolean用true或false表示的是1bit的信息,这一点想必是没有问题的。

对于1bit的信息,理论上只需要占用1个bit位就可以表示了。但是,实际中是否真的占用1个bit位呢?之前的贴子里有说占1byte(8bit)的,使用最低位表示,其余为0;有说用int表示的。还有或用1bit表示的(这个应该就不对了,Java中字节是最小内存寻址单位)。

在Java的官方文档Primitive Data Types里,对boolean的描述如下:

boolean: The boolean data type has only two possible values: true and false. Use this data type for simple flags that track true/false conditions. This data type represents one bit of information, but its "size" isn't something that's precisely defined.

可以看出,文中对int、char等的描述中都说明了占用字节数,唯独对boolean的描述中只是说,代表1bit的信息,但(内存)“大小”并没有精确定义。

猜测这是需要JVM自己定义优化 。

在stackoverflow上也有讨论的帖子What is the size of a boolean variable in java?,排在第一位的答案就一句话:

Its virtual machine dependent.

另一个投票很多的答案写了代码来测试,如下:

class LotsOfBooleans
{
    boolean a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af;
    boolean b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf;
    boolean c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf;
    boolean d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, da, db, dc, dd, de, df;
    boolean 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
    {        
        LotsOfBooleans[] first = new LotsOfBooleans[SIZE];
        LotsOfInts[] second = new LotsOfInts[SIZE];
                                           
        System.gc();
        long startMem = getMemory();
                                           
        for (int i=0; i < SIZE; i++)
        {
            first[i] = new LotsOfBooleans();
        }
                                           
        System.gc();
        long endMem = getMemory();
                                           
        System.out.println ("Size for LotsOfBooleans: " + (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 ? 1 : 0) + second[i].a0;
        }
        System.out.println(total);
    }
                                           
    private static long getMemory()
    {
        Runtime runtime = Runtime.getRuntime();
        return runtime.totalMemory() - runtime.freeMemory();
    }
}

运行结果是:

Size for LotsOfBooleans: 87978576
Average size: 87.978576
Size for LotsOfInts: 328000000
Average size: 328.0

我之前使用过runtime.totalMemory() - runtime.freeMemory()来计算内存,不过感觉不太靠谱。因为分配的mem是根据需要变动的。不过看这个结果,在大量数据的时候还是可以的。

代码中的数组是80个,所以平均下来Boolean是1byte,Int是4byte。

不过也有人说在JVM中,boolean和boolean[]的处理是不一样的。正好有本《Java虚拟机规范(Java SE 7)》,查阅了下boolean章节如下:

虽然Java虚拟机定义了boolean这种数据类型, 只对它提供了非常有限的支持。在Java虚拟机中没有任何提供boolean值专用的字节码指令,在Java语言之中设及到boolean类型值的运算,在编译之后都使用Java虚拟机中的int数据类型来代替。

Java虚拟机直接支持boolean类型的数组,虚拟机的newarray指令可以创建这种数组。boolean的数组类型的访问与修改公用byte类型数组的baload和bastore指令。

这样一来,就比较明确了:

JVM中,对boolean的支持有限,所以是按照int处理的;对boolean数组是直接支持的,按照byte数组处理。

参考资料:

  1. JAVA 8种基本类型所占内存分析

  2. java中的 boolean 在内存中占多少字节?

  3. Primitive Data Types

  4. What is the size of a boolean variable in java?

  5. 《Java虚拟机规范(Java SE 7)》