简单说明
1.什么是sizeof?
在C语言中,sizeof是一个判断数据类型长度符的关键字,它可以返回一个对象或者类型所占的内存字节数。
例如,在C语言中,我们可以通过
printf("%d",sizeof(int));
可以输出int所占字节数。
2.为什么Java中没有sizeof()?
Java是一种纯面向对象的编程语言,它将内存管理的细节都交给Java Virtual Machine(JVM)进行。
同时Java是一种跨平台的语言,可移植性好,它在数据类型在机器中的大小都相同。
而在C/C++中需要sizeof是因为移植,不同的数据类型在不同的机器上大小可能不同,程序员必须知道对应的数据类型大小。
#详细介绍1.数据类型
- Java基本数据类型
int 32bit
short 16bit
long 64bit
byte 8bit
char 16bit
float 32bit
double 64bit
boolean 1bit - Java基本数据类型封装类
Integer // 4 byte
Short // 2 byte
Long // 8 byte
Byte // 1 byte
Character: // 2 byte
Float // 4 byte
Double // 8 byte
2.java无sizeof
这是一个程序,java中没有现成的sizeof的实现,原因主要是java中的基本数据类型的大小都是固定的,所以看上去没有必要用sizeof这个关键字。
Java中模拟c中对sizeof的实现
思路:利用java中GC内存回收前后的heap size差别,得出每个object的大小
实现的想法是这样的:java.lang.Runtime类中有一些简单的能涉及到内存管理的函数:
方法返回类型 | 方法名 | 说明 |
---|---|---|
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. |
3.代码
(1)检测类型代码
private static void calSize() {
System.out.println("Integer: " + Integer.SIZE/8); // 4
System.out.println("Short: " + Short.SIZE/8); // 2
System.out.println("Long: " + Long.SIZE/8); // 8
System.out.println("Byte: " + Byte.SIZE/8); // 1
System.out.println("Character: " + Character.SIZE/8); // 2
System.out.println("Float: " + Float.SIZE/8); // 4
System.out.println("Double: " + Double.SIZE/8); // 8
}
(2)检测代码
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();
}
解释如下:
这个例子写的很好,正好说明了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.csdn.net/yaoqing1995/article/details/53945963
http://blog.csdn.net/ithomer/article/details/7310008