因为跟同事大哥一起看一个社区的jira,不得不恶补了一下java的类内存分配与使用计算方法。原文请参照http://www.codeinstructions.com/2008/12/java-objects-memory-structure.html 。不得不说,一件事情做进去真的越来越复杂。

     在c和c++中,程序员可以自由的操纵内存数据,包括内存分配,内存释放等等,在java中这些繁琐(或者也可以说其实不错)的特性完全由虚拟机搞定,不用再管内存分配回收,看起来相当爽,但是到底类占用了多少空间,如何计算,对于大内存应用的程序,如hadoop hbase等有十分现实的意义。

     首先描述一下内存使用情况的分类,一种是shallow size,一种是是deep size。这里主要说明一下shallow size的计算方法。

     1、没有实力属性的类内存占用情况

     每个java类(除了数组)都占用2个字(word)的头信息(header),header的第一个字(word)内容包括有类的hash值,锁信息以及一些存活时间信息等。header的第二个字(word)包含有类的引用。

every object is aligned to an 8 bytes granularity

      2、类内部内存使用情况

     类头部8字节后面是属性情况,基本数据类型内存的使用情况按照我们从课本上解释的,如图:

     

java 按比例随机 java按照比例分配_java 按比例随机

     但是注意,这些类型在内存的分配是需要对齐的!对齐的原因可以参看这篇文章,http://www.devx.com/tips/Tip/13265 简单的说就是为了性能方面的考虑,int是4bytes对齐,double是8个bytes对齐。在对齐的方式上,jvm是做了优化的,即在一个类中,数据是按照以下顺序进行存储的。 

  1. doubles and longs
  2. ints and floats
  3. shorts and chars
  4. booleans and bytes
  5. references

    这样能够最小限度的减少padding,节约内存。如对一个类   



class MyClass {
byte a;
int c;
boolean d;
long e;
    Object f;        
}



    如果按照顺序存储在内存中,则总共需要40bytes    



[HEADER:  8 bytes]  8
[a:       1 byte ]  9
[padding: 3 bytes] 12
[c:       4 bytes] 16
[d:       1 byte ] 17
[padding: 7 bytes] 24
[e:       8 bytes] 32
[f:       4 bytes] 36
[padding: 4 bytes] 40



   按照jvm的规则存取,则只需要32bytes



[HEADER:  8 bytes]  8
[e:       8 bytes] 16
[c:       4 bytes] 20
[a:       1 byte ] 21
[d:       1 byte ] 22
[padding: 2 bytes] 24
[f:       4 bytes] 28
[padding: 4 bytes] 32



    规则(2)jvm内部存储属性是按照先保存long,double;然后int,float;然后char,short;然后byte,boolean,最后是类的引用(reference)。

   3、子类内存分布

    规则(3)子类和父类的属性不会混合在一起重排保存,父类先保存,子类后保存    



class A {
long a;
int b;
int c;
}

class B extends A {
long d;
}



[HEADER:  8 bytes]  8
[a:       8 bytes] 16
[b:       4 bytes] 20
[c:       4 bytes] 24
[d:       8 bytes] 32



Rule 4: Between the last field of the superclass and the first field of the subclass there must be padding to align to a 4 bytes boundary.

Rule 5: When the first field of a subclass is a double or long and the superclass doesn't align to an 8 bytes boundary, JVM will break rule 2 and try to put an int, then shorts, then bytes, and then references at the beginning of the space reserved to the subclass until it fills the gap. 

   rule4,rule5参照原文。

   对于数组加了4个字节的length信息,所以数组的header是12个bytes。