转载

【深入浅出-JVM】(57):深堆、浅堆

浅堆表示一个对象结构所占用的大小(对象头+实例数据+对齐填充,不包括内部引用 对象大小)

深堆表示一个对象被 GC 回收后,可以真实释放的内存大小(保留空间)

对象

对象 = 对象头 + 实例数据 + 对齐填充

对象头

对象头 = 标记部分 + 原始对象引用

标记部分包括 hashcode、gc 分代年龄、锁状态标志、线程持有锁、偏向线程锁id,偏向时间戳,这一部分在32位机器上为 4 byte,64 位机器上为 8byte

原始对象引用是对象的指针、通过这个指针找到对象的实例、该数据可以压缩,这一部分在 32 位机器上为 4 byte,64位机器上为 8byte,如果开启了压缩(UseCompreddedOops),大小为 4byte,jdk8默认开启压缩

结论:一个对象头大小(64 位) = 12 byte(压缩) / 16 byte(未压缩)

实例数据

类型 大小(byte)
byte 1
boolean 1
char 2
short 2
int 4
float 4
double 8
long 8

对齐填充

任何对象都以 8 byte 来对齐,所以对象的大小为 8 的整数倍

保留内存

只能通过该对象访问的对象浅堆之和(其他对象可以访问到的排除掉)

举例:A,B,C,D,E 5个对象,A 引用 B,C。D 引用C、E

A 的深堆 = A + B + C

A 的保留内存大小 = A +B ,因为 D 引用了 C

例子

实战深堆、浅堆——学生访问网站记录

-XX:+HeapDumpBeforeFullGC -XX:HeapDumpPath=stu.hprof

WebPage 网站记录

package com.mousycoder.mycode.thinking_in_jvm;

/**
 * @version 1.0
 * @author: mousycoder
 * @date: 2019-07-29 10:38
 */
public class WebPage {

    private String url;

    private String content;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

Student

package com.mousycoder.mycode.thinking_in_jvm;

import java.util.List;
import java.util.Vector;

/**
 * @version 1.0
 * @author: mousycoder
 * @date: 2019-07-29 10:37
 */
public class Student {

    private int id;

    private String name;

    private List<WebPage> history = new Vector<WebPage>();



    public void visit(WebPage webPage){
        history.add(webPage);
    }


    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }


    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<WebPage> getHistory() {
        return history;
    }

    public void setHistory(List<WebPage> history) {
        this.history = history;
    }
}

TraceStudent

package com.mousycoder.mycode.thinking_in_jvm;

import java.util.List;
import java.util.Vector;

/**
 * @version 1.0
 * @author: mousycoder
 * @date: 2019-07-29 10:39
 */
public class TraceStudent {

    static List<WebPage> webPages = new Vector<WebPage>();

    public static void createWebPages(){
        for (int i = 0; i < 100; i++) {
            WebPage wp = new WebPage();
            wp.setUrl("http://www."+Integer.toString(i)+".com");
            wp.setContent(Integer.toString(i));
            webPages.add(wp);
        }
    }


    public static void main(String[] args) {
        createWebPages();
        Student st3 = new Student(3,"billy");
        Student st5 = new Student(5,"alice");
        Student st7 = new Student(7,"taotao");

        for (int i = 0; i < webPages.size(); i++) {
            if (i % st3.getId() == 0) {
                st3.visit(webPages.get(i));  // 访问能被id 整除的网站
            }

            if (i % st5.getId() == 0 ) {
                st5.visit(webPages.get(i));
            }

            if (i % st7.getId() == 0) {
                st7.visit(webPages.get(i));
            }

        }

        webPages.clear();
        System.gc();
    }
}

用 MAT 打开stu.hprof 打开线程视图,可以看到每个student实例的 shallow heap 为 24 bytes (2 个 ref 引用 history + name = 4 byte * 2 = 8 byte ,1 个 int 类型 = 4 byte ,标记部分 8 byte ,一共 20 byte,向 8byte 靠齐就是 24 byte)

【深入浅出-JVM】(57):深堆、浅堆

webpage 的深堆为 152 byte (80 + 48 + 24)

【深入浅出-JVM】(57):深堆、浅堆

elementData 深堆大小为 96 byte (每个引用 4 个字节,合计 4*20=80 字节,数组对象头 8 个 字节,数组长度 4 个字节 ,合计 80 + 8 + 4 = 92 字节,向 8 字节对齐填充后,为 96 字节)

【深入浅出-JVM】(57):深堆、浅堆
原文  http://mousycoder.com/thinking-in-jvm/57/
正文到此结束
Loading...