zoukankan      html  css  js  c++  java
  • jvm字节占用空间分析

    一个对象实例占用了多少字节,消耗了多少内存?这样的问题在c或c++里使用sizeof()方法就可以得到明确答案,在java里好像没有这样的方法(java一样可以实现),不过通过jmap工具倒是可以查看出一个对象的占用内存的大小,这里介绍一种通过分析java代码计算内存使用情况的方法。

    注意,一下讨论的情况都是基于32位机,不适用用64位机,JVM是sun的HotSpot,不同的虚拟机实现可能会不同

    规则一:每个对象被按照8bytes粒度对齐(数组除外)

    在jvm中每个对象(数组除外)都有一个头,这个头有两个字,第一个字存储的时对象的一些标志位信息,例如:锁标志位、经历了几次gc等信息,第二个字是一个引用,指向了这个类的类信息。这里jvm给这两个字留了8个字节的空间(这个为啥用8个字节空间不是很清楚,一个字即两个字节,我一直认为4个字节就够了)

    按规则一:new Object();这个Object实例就占用了8个字节

    规则二:为类属性分配存储空间时不是按照类中定义的属性顺序,而是按如下的顺序:

                1、doublelong;----8bytes

                2、intfloat;----4bytes

                3、charshort;----2bytes

                4、booleanyte;----1bytes

                5、reference;----4bytes

    例如:

    Java代码  

    public class A {   

        byte a;   

        char b;   

        int c;   

        long d;   

        Object e;   

    }   

    属性        需要字节数        累积字节数

    header        8bytes        8

    long:d        8bytes        16

    int:c        4bytes        20

    char:b        2bytes        22

    byte:a        1bytes        23

    Object:e        4bytes        27

             padding 5bytes        32 

    最后一行padding 5bytes的目的是,规则一中描述每个对象按照8个字节的粒度对齐,这样下一个分配的对象的开始位置必须在8的倍数上,而离27最近的8的倍数是32,因此加了5bytes。A占用32bytes

    可以用jmap看一下这个计算是否准确

    规则三:对于继承时,要按照规则二先计算父类的类属性占用情况,再按照规则二计算子类的类属性占用情况,不能将父类和子类的属性混合在一起按规则二分配。

    例如:

    Java代码  

    class B{  

        long a;  

        int b;  

        int c;  

    }  

    class BB extends B{  

        long d;  

    }  

     属性        占用字节数        累计字节数

    header        8        8

    a        8        16

    b        4        20

    c        4        24

    d        8        32

    这里累计字节正好是8的倍数,满足规则一,因此不用padding字节。BB对象内存占用了32bytes

    规则四:父类的最后一个属性和子类第一个属性必须按4个字节的倍数对齐

    例如:

    Java代码  

    class B{  

        long a;  

        int b;  

        char c;  

    }  

    class BB extends B{  

        long d;  

    }  

    属性        占用的字节        累计字节

    head        8        8

    a        8        16

    c        2        18

             padding 2        20

    d        8        28

             padding 4        32

    第一次padding2是因为属性c分配内存后,不满足父类最后一个属性和子类第一个属性按4字节粒度对齐(18除4除不开),因此需要添加两个字节使其可以按4字节粒度对齐。

    第二次paadding4是依据规则一

    规则五:当子类的第一个属性是double或long,但是父类不能按8字节粒度对齐时,子类内存分配时的顺序将不按规则二进行,而是按:先intfloat、charshort、booleanyte、reference、longdouble

    例如:

    Java代码  

    class A{  

        byte a;  

    }  

    class B extends A{  

        long b;  

        short c;  

        byte d;  

    }  

    属性        占用字节数        累计占用字节数

    head        8        8

    a        1        9

             padding 3        12

    c        2        14

    d        1        15

             padding 1        16

    b        8        24

     第一次 padding 3是根据规则四

     第二次 padding 1是因为b属性是8个字节,因此需要按8个字节粒度对齐。B占用24bytes

     对于数组,与普通对象不同的是在头部,头部多了4个字节用于存储长度信息。因此数组的head是12bytes而不是8bytes

  • 相关阅读:
    [洛谷P4725]【模板】多项式对数函数
    [洛谷P4841]城市规划
    [洛谷P4346][CERC2015]ASCII Addition
    [洛谷P3978][TJOI2015]概率论
    [洛谷P4656][CEOI2017]Palindromic Partitions
    [洛谷P4889]kls与flag
    [洛谷P3810]【模板】三维偏序(陌上花开)
    [洛谷P2613]【模板】有理数取余
    [bzoj4945][Noi2017]游戏
    [洛谷P4151][WC2011]最大XOR和路径
  • 原文地址:https://www.cnblogs.com/tonychai/p/4789438.html
Copyright © 2011-2022 走看看