在java中,基本类型的占用字节数,大家都不是很陌生,由于java程序都是运行在JVM上的,所以java中的类型字节位数不会受平台的限制。java中各种类型占位如下:
| Tables | Are |
|---|---|
| int | 32bit |
| short | 16bit |
| long | 64bit |
| byte | 8bit |
| char | 16bit |
| float | 32bit |
| double | 64bit |
| boolean | 1bit,This data type represents one bit of information, but its “size” isn’t something that’s precisely defined.(ref) |
具体字节如上所述,下面重点讨论char型和boolean型。
char
char,不同在C/C++中的ASCII编码,在java中使用的是Unicode为char编码,Java中使用Unicode的原因是,Java的Applet允许全世界范围内运行,那它就需要一种可以表述人类所有语言的字符编码,Unicode编码的特性和容纳字符数量决定了char类型是双字节的(在java出生的时候,Unicode编码的码点上限还是 0xFFFF,即使现在,非 BMP 文字也比较罕见,设计成两字节是比使用 UTF-8 之类「过于变长」的编码更方便的。1990 年代出的、和 Unicode 有关的库啊,语言啊,API 啊基本上都是这样设定。)。
boolean
为什么要问这个问题,首先在Java中定义的八种基本数据类型中,除了其它七种类型都有明确的内存占用字节数外,就boolean类型没有给出具体的占用字节数,因为对虚拟机来说根本就不存在 boolean 这个类型,boolean类型在编译后会使用其他数据类型来表示,那boolean类型究竟占用多少个字节?带着疑问,随便网上一搜,答案五花八门,基本有以下几种:
1个bit
理由是boolean类型的值只有true和false两种逻辑值,在编译后会使用1和0来表示,这两个数在内存中只需要1位(bit)即可存储,位是计算机最小的存储单位。
1个字节
理由是虽然编译后1和0只需占用1位空间,但计算机处理数据的最小单位是1个字节,1个字节等于8位,实际存储的空间是:用1个字节的最低位存储,其他7位用0填补,如果值是true的话则存储的二进制为:0000 0001,如果是false的话则存储的二进制为:0000 0000。
4个字节
理由来源是《Java虚拟机规范》一书中的描述:“虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达式所操作的boolean值,在编译之后都使用Java虚拟机中的int数据类型来代替,而boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8位”。这样我们可以得出boolean类型占了单独使用是4个字节,在数组中又是1个字节。
显然第三条是更准确的说法,那虚拟机为什么要用int来代替boolean呢?为什么不用byte或short,这样不是更节省内存空间吗。大多数人都会很自然的这样去想,我同样也有这个疑问,经过查阅资料发现,使用int的原因是,对于当下32位的处理器(CPU)来说,一次处理数据是32位(这里不是指的是32/64位系统,而是指CPU硬件层面),具有高效存取的特点。
最后的总结:
根据http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html官方文档的描述:
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.
可以看出,boolean类型没有给出精确的定义,《Java虚拟机规范》给出了4个字节,和boolean数组1个字节的定义,具体还要看虚拟机实现是否按照规范来,所以1个字节、4个字节都是有可能的。这其实是运算效率和存储空间之间的博弈,两者都非常的重要。
原文链接:http://www.jianshu.com/p/2f663dc820d0 文/威哥干Java(简书作者)
Java中模拟c中对sizeof的实现
思路:利用java中GC内存回收前后的heap size差别,得出每个object的大小
这是一个程序,java中没有现成的sizeof的实现,原因主要是java中的基本数据类型的大小都是固定的,所以看上去没有必要用sizeof这个关键字。实现的想法是这样的:java.lang.Runtime类中有一些简单的能涉及到内存管理的函数:
Every Java application has a single instance of class Runtime that allows the application to interface with the environment in which the application is running. The current runtime can be obtained from the getRuntime method.
| return type | function |
|---|---|
| long | freeMemory() Returns the amount of free memory in the Java Virtual Machine. |
| void | gc() Runs the garbage collector. |
| static Runtime | getRuntime() Returns the runtime object associated with the current Java application. |
| long | maxMemory() Returns the maximum amount of memory that the Java virtual machine will attempt to use. |
| void | runFinalization() Runs the finalization methods of any objects pending finalization. |
使用这些简单的内存访问,可以得到内存的一些情况,我们通过建立一个大的某个类的数组,来查看内存用了多少,进而可以求得类的大小。
private static void calSize2() {
runGC();
long heap1 = 0;
final int count = 100000;
Object[] objs = new Object[count];
for(int i=-1; i<count; i++) {
Object obj = null;
obj = new Object(); // 8
// obj = new Integer( i ); // 16
// obj = new Short( (short)i ); // 16
// obj = new Long( i ); // 16
// obj = new Byte( (byte)0 ); // 16
// obj = new Character( (char)i ); // 16
// obj = new Float( i ); // 16
// obj = new Double( i ); // 16
// obj = new Boolean( true ); // 16
// obj = new String(); // 40
if(i<0){
obj = null;
runGC();
heap1 = usedMemory(); // before memory size
} else {
objs[i] = obj;
}
}
runGC();
long heap2 = usedMemory(); // after memory size
final int size = (int)Math.round( (heap2 - heap1)/(double)count );
System.out.println("heap1 = " + heap1 + "; heap2 = " + heap2);
System.out.println("heap2-heap1 = " + (heap2 - heap1) + "; " + objs[0].getClass().getSimpleName() + " size = " + size);
for(int i=0; i<count; i++) {
objs[i] = null;
}
objs = null;
runGC();
}
private static void runGC() {
for(int i=0; i<4; i++) {
long usedMem1 = usedMemory();
long usedMem2 = Long.MAX_VALUE;
for(int j=0; (usedMem1<usedMem2) && (j<500); j++) {
rTime.runFinalization();
rTime.gc();
Thread.yield();
usedMem2 = usedMem1;
usedMem1 = usedMemory();
}
}
}
private static long usedMemory() {
return rTime.totalMemory() - rTime.freeMemory();
}
注意:Object[] objects = new Object[count];
只是分配了数组空间,没有分配对象的空间。数组中只有引用而已。
结论:下代码测试基本对象时,得出的结果象下面:
Object obj = null;
obj = new Object(); // 8
obj = new Integer( i ); // 16
obj = new Short( (short)i ); // 16
obj = new Long( i ); // 16
obj = new Byte( (byte)0 ); // 16
obj = new Character( (char)i ); // 16
obj = new Float( i ); // 16
obj = new Double( i ); // 16
obj = new Boolean( true ); // 16
obj = new String(); // 40
怎么会这样呢???解释如下:
这个例子写的很好,正好说明了java中基本类型封装对象所占内存的大小.
1.简单的Object对象要占用8个字节的内存空间,因为每个实例都至少必须包含一些最基本操作,比如:wait()/notify(),equals(), hashCode()等
2.使用Integer对象占用了16个字节,而int占用4个字节,说了封装了之后内存消耗大了4倍
3.那么Long看起来比Integer对象应该使用更多空间,结果Long所占的空间也是16个字节.
那么就正好说明了JVM的对于基本类型封装对象的内存分配的规则是如下:
Object所占内存(8个字节)+最大基本类型(long)所占内存(8个字节) = 16字节.
JVM强制使用8个字节作为边界.
所以所有基本类型封装对象所占内存的大小都是16字节.
但是还是有区别,比如:Integer对象虽然占用了16个字节的内存,但是只是利用了 Object所占内存(8个字节)+int所占内存(4个字节) = 12字节.
还有4个字节根本没有被使用.
转载自http://blog.youkuaiyun.com/sunboy_2050/article/details/7310008
Java基本类型内存占用解析
本文详细探讨了Java中基本类型的内存占用情况,特别是char和boolean类型的具体实现细节,并通过模拟C语言中的sizeof操作来估算Java对象的内存大小。

被折叠的 条评论
为什么被折叠?



