美文网首页
JVisualVm 使用以及 Java 中类大小的疑惑

JVisualVm 使用以及 Java 中类大小的疑惑

作者: 放开那个BUG | 来源:发表于2021-12-23 23:59 被阅读0次

    1、前言

    之前我们在 JVisualVM 中,经常能看到对象大小,如图所示:


    对象大小

    然后,我们理所当然的认为这个对象以及对象所引用的对象总共这么大,然而这种认知是错误的。比如,我做如下实验,创建一个 Person 类,Person 类里就只有一个简单的 name 属性。代码如下:

    public class Person {
    
        private String name;
    
        public Person(String name) {
            this.name = name;
        }
    }
    
    public class NIUBI {
    
        private String name;
    
        private String desc;
    
        private List<Person> personList = new ArrayList<>();
    
        public NIUBI(String name, String desc) {
            this.name = name;
            this.desc = desc;
    
            for(int i = 0; i < 5000000; i++){
                this.personList.add(new Person("mamammmammm" + i));
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            NIUBI niubi = new NIUBI("22", "dd");
    
            System.out.println(ClassLayout.parseInstance(niubi).toPrintable());
            Thread.sleep(5000);
            System.out.println(RamUsageEstimator.sizeOf(niubi) / 1024 / 1024);
            System.out.println(RamUsageEstimator.shallowSizeOf(niubi));
    
    
            Thread.sleep(500000 * 1000);
        }
    }
    

    这个对象看起来就很大,然后我用一个 java 中估算对象大小的工具来打印对象大小。我分别用了:

    <dependency>
                <groupId>org.openjdk.jol</groupId>
                <artifactId>jol-core</artifactId>
                <version>0.9</version>
            </dependency>
    

    这个主要是打印对象的内存布局的。

    <dependency>
                <groupId>org.apache.lucene</groupId>
                <artifactId>lucene-core</artifactId>
                <version>4.0.0</version>
            </dependency>
    

    这个主要是计算对象大小以及该对象引用的数据大小。

    使用两个不同的工具是想看一下每个工具得到的结果是否正确,防止一个工具得出偏颇的结局。

    2、现象

    运行代码,得到如下输出:


    输出

    可见 NIUBI 对象本身的大小才 24B,但是 NIUBI 加上引用的 Person 对象总共有480MB。然后我们从 JVisualVm 来查看相应的类:


    NIUBI
    Person

    NIUBI 大小只有 40B(跟24B差别不大,可能是不同工具的问题),Person 大小有接近114MB(String 也算对象)。从上图可以看到,JVisualVm 查看相应的大小时,只是查看对象本身的大小,并不是对象 + 引用的对象大小,要不然 NIUBI 也应该是480MB才对。

    3、结论

    我们在 JVisualVm 查看堆内存的时候,发现有某个对象可能几百万,然后占用内存才2G左右,不能以为这个对象 + 引用对象大小就2G,可能算了此对象引用的对象后,你会发现实际占用内存比2G多得多,所以才会导致内存爆炸。

    一般可以根据最顶层的类(这里是 NIUBI)来计算保留大小,也能大致从 GcRoots 出发,找到 NIUBI + 其所引用的所有类的大小。


    查保留

    4、参考资料

    1、https://www.yourkit.com/docs/java/help/sizes.jsp

    相关文章

      网友评论

          本文标题:JVisualVm 使用以及 Java 中类大小的疑惑

          本文链接:https://www.haomeiwen.com/subject/qiykqrtx.html