欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java對(duì)象的內(nèi)存布局全流程

 更新時(shí)間:2022年05月05日 15:32:27   作者:舊時(shí)明月丶  
這篇文章主要介紹了Java對(duì)象的內(nèi)存布局全流程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

開(kāi)始先拋出一個(gè)問(wèn)題:一個(gè)對(duì)象o,Object o = new Object();創(chuàng)建完成后會(huì)占用多少字節(jié)的內(nèi)存?

要能回答這個(gè)問(wèn)題,就需要了解java對(duì)象的內(nèi)存布局。

對(duì)象內(nèi)存布局

一個(gè)Java對(duì)象在內(nèi)存中包括對(duì)象頭、實(shí)例數(shù)據(jù)和對(duì)齊填充三個(gè)部分。如下圖所示:

在這里插入圖片描述

對(duì)象頭

  • Mark Word:包含一系列的標(biāo)記位比如hashcode、GC分代年齡、偏向鎖位,鎖標(biāo)志位等。這個(gè)Mark Word在對(duì)象被加了不同量級(jí)的鎖時(shí)所包含的內(nèi)容和布局都有所不同,這涉及到鎖升級(jí)的知識(shí),暫不展開(kāi)討論
  • Klass Pointer:是一個(gè)指針,指向描述這個(gè)對(duì)象類(lèi)型的元對(duì)象,例如Object.class,User.class等

實(shí)例數(shù)據(jù)

  • instance data:描述成員變量的信息,如果成員變量是引用類(lèi)型,那么它就是一個(gè)指針。instance data的大小是所有成員變量的占用空間(基本數(shù)據(jù)類(lèi)型大小+指針大?。?/li>

對(duì)齊

  • padding:在java中,為了能夠更加高效的利用內(nèi)存空間,會(huì)將對(duì)象大小設(shè)定為8bytes的整數(shù)倍,如果對(duì)象頭+實(shí)例數(shù)據(jù)的大小不是8bytes的倍數(shù),那么會(huì)在padding區(qū)域填充幾個(gè)字節(jié),使得對(duì)象占用空間是8bytes的倍數(shù)

那么對(duì)象布局中各個(gè)部分占用內(nèi)存空間到底多大呢?

對(duì)象占用內(nèi)存空間

由于目前64位操作系統(tǒng)已經(jīng)基本普及,下面只分析64位操作系統(tǒng)下的情況

指針壓縮

在64位系統(tǒng)中,一個(gè)指針占64 bits也就是8 bytes,而在32位系統(tǒng)中指針只占4個(gè)字節(jié),于是為了能夠減少內(nèi)存消耗,從JDK1.6開(kāi)始,JVM會(huì)默認(rèn)支持指針壓縮,會(huì)將指針大小壓縮成4個(gè)字節(jié),

這涉及到兩個(gè)參數(shù)-XX:+UseCompressedOops,-XX:+UseCompressedClassPointers。

  • UseCompressedOops:oops: ordinary object pointer,普通對(duì)象指針壓縮,例如Object o = new Object();其中o就是個(gè)指向new Object()對(duì)象的指針,o在指針壓縮前占用8個(gè)字節(jié),在指針壓縮后占用4個(gè)字節(jié)
  • UseCompressedClassPointers:壓縮Klass Pointer,壓縮前8個(gè)字節(jié),壓縮后4個(gè)字節(jié)

對(duì)象頭

Mark Word占8個(gè)字節(jié)

  • Klass Pointer:開(kāi)啟(默認(rèn))壓縮4個(gè)字節(jié),不開(kāi)啟壓縮8個(gè)字節(jié)

實(shí)例數(shù)據(jù)

  • instance data:根據(jù)實(shí)際情況計(jì)算:如果成員變量是基本數(shù)據(jù)類(lèi)型,那么占用空間就是基本數(shù)據(jù)類(lèi)型的大小,Java的8大基本數(shù)據(jù)類(lèi)型的大小如下:
數(shù)據(jù)類(lèi)型占用空間bytes
byte1
short2
int4
long8
float4
double8
char2
boolean1

如果成員變量是引用類(lèi)型,那么就是一個(gè)指針大?。ㄩ_(kāi)啟指針壓縮占4字節(jié),不開(kāi)啟指針壓縮8字節(jié))

對(duì)齊

  • padding:如果對(duì)象頭+實(shí)例數(shù)據(jù)的大小不是8 bytes的倍數(shù),那么就填充這個(gè)區(qū)域,使得對(duì)象占用空間能被8個(gè)字節(jié)整除(最小情況)

口說(shuō)無(wú)憑,下面將會(huì)通過(guò)實(shí)驗(yàn)證明

證明對(duì)象內(nèi)存布局

我們需要引用一個(gè)依賴(lài):openjdk提供的jol-core:

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

1.查看默認(rèn)情況下沒(méi)有成員變量的對(duì)象布局

示例代碼:

public class TestObj {
    public static void main(String[] args) {
        // 創(chuàng)建對(duì)象
        Object o = new Object();
        // 獲得對(duì)象布局內(nèi)容
        String s = ClassLayout.parseInstance(o).toPrintable();
        // 打印對(duì)象布局
        System.out.println(s);
    }
}

輸出結(jié)果:

在這里插入圖片描述

其中對(duì)象頭(object header)有三個(gè),前兩個(gè)是Mark Word一共8個(gè)字節(jié),后面一個(gè)是Klass Pointer,占4個(gè)字節(jié),由于沒(méi)有成員變量,所以實(shí)例數(shù)據(jù)沒(méi)有占用空間,而最后4個(gè)字節(jié)描述信息為:loss due to the next object alignment,意思就是為了與下一個(gè)對(duì)象對(duì)齊而丟失的部分,也就是對(duì)齊填充空間

2.證明Klass Pointer在不開(kāi)啟壓縮的情況下占用8個(gè)字節(jié)

我們只需要在jvm參數(shù)上加上-XX:-UseCompressedClassPointers即可,在IDEA工具中可以設(shè)置啟動(dòng)參數(shù):

在這里插入圖片描述

還是運(yùn)行上述代碼,運(yùn)行程序結(jié)果:

在這里插入圖片描述

如上圖所示,對(duì)象頭已經(jīng)占用16個(gè)字節(jié),前8個(gè)字節(jié)是Mark Word,后8個(gè)字節(jié)就是未壓縮的Klass Pointer。我們還注意到對(duì)齊填充也沒(méi)有了,原因是此時(shí)對(duì)象占用空間16個(gè)字節(jié)已經(jīng)是8bytes的倍數(shù),所以不需要填充,這完全印證了前面的分析

3.證明實(shí)例數(shù)據(jù)的存在以及大小

示例代碼:

public class TestObj {
    public static void main(String[] args) {
        // 創(chuàng)建對(duì)象
        User user = new User(1, "zhangsan");
        // 獲得對(duì)象布局內(nèi)容
        String s = ClassLayout.parseInstance(user).toPrintable();
        // 打印對(duì)象布局
        System.out.println(s);
    }
}
class User {
    private int id;
    private String name;
    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

打印結(jié)果:

在這里插入圖片描述

如上圖所示,int類(lèi)型的id占用4個(gè)字節(jié),指向字符串對(duì)象的name指針占用4個(gè)字節(jié),加上對(duì)齊,對(duì)象一共占用24 bytes

4.最后驗(yàn)證不開(kāi)啟指針壓縮的情況下指針占用8 bytes

只需在jvm參數(shù)上加上-XX:-UseCompressedOops:

在這里插入圖片描述

還是運(yùn)行上面的代碼,打印結(jié)果:

在這里插入圖片描述

很顯然,此時(shí)name指針已經(jīng)占用了8個(gè)字節(jié)

一般來(lái)說(shuō),UseCompressedClassPointers和UseCompressedOops是默認(rèn)開(kāi)啟的,我們無(wú)需關(guān)心也無(wú)需修改。但是有個(gè)隱藏的細(xì)節(jié)就是:UseCompressedClassPointers的開(kāi)啟依賴(lài)UseCompressedOops的開(kāi)啟,并且開(kāi)啟UseCompressedOops 也默認(rèn)強(qiáng)制開(kāi)啟UseCompressedClassPointers,關(guān)閉UseCompressedOops 默認(rèn)關(guān)閉UseCompressedClassPointers。

至此,關(guān)于java對(duì)象的內(nèi)存布局已經(jīng)有了一個(gè)基本的了解,那么文章一開(kāi)始的問(wèn)題現(xiàn)在應(yīng)該能很輕松的回答:16個(gè)字節(jié)。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Okhttp在SpringBoot中的應(yīng)用實(shí)戰(zhàn)記錄(太強(qiáng)了)

    Okhttp在SpringBoot中的應(yīng)用實(shí)戰(zhàn)記錄(太強(qiáng)了)

    這篇文章主要給大家介紹了關(guān)于Okhttp在SpringBoot中應(yīng)用實(shí)戰(zhàn)的相關(guān)資料,在Spring Boot中使用OkHttp主要是為了發(fā)送HTTP請(qǐng)求和處理響應(yīng),OkHttp是一個(gè)高效、易用的HTTP客戶(hù)端庫(kù),它具有簡(jiǎn)潔的API和強(qiáng)大的功能,需要的朋友可以參考下
    2023-12-12
  • 一篇文章帶你使用SpringBoot基于WebSocket的在線群聊實(shí)現(xiàn)

    一篇文章帶你使用SpringBoot基于WebSocket的在線群聊實(shí)現(xiàn)

    這篇文章主要介紹了一篇文章帶你使用SpringBoot基于WebSocket的在線群聊實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • Spring IOC中的Bean對(duì)象用法

    Spring IOC中的Bean對(duì)象用法

    這篇文章主要介紹了Spring IOC中的Bean對(duì)象用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java線程安全狀態(tài)專(zhuān)題解析

    Java線程安全狀態(tài)專(zhuān)題解析

    線程安全是多線程編程時(shí)的計(jì)算機(jī)程序代碼中的一個(gè)概念。在擁有共享數(shù)據(jù)的多條線程并行執(zhí)行的程序中,線程安全的代碼會(huì)通過(guò)同步機(jī)制保證各個(gè)線程都可以正常且正確的執(zhí)行,不會(huì)出現(xiàn)數(shù)據(jù)污染等意外情況
    2022-03-03
  • Java 異步編程實(shí)踐_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java 異步編程實(shí)踐_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    異步編程提供了一個(gè)非阻塞的,事件驅(qū)動(dòng)的編程模型。下面通過(guò)本文給大家介紹Java 異步編程實(shí)踐,感興趣的的朋友一起看看吧
    2017-05-05
  • spring data jpa開(kāi)啟批量插入、批量更新的問(wèn)題解析

    spring data jpa開(kāi)啟批量插入、批量更新的問(wèn)題解析

    這篇文章主要介紹了spring data jpa開(kāi)啟批量插入、批量更新問(wèn)題,本文通過(guò)圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2021-07-07
  • Java中如何獲取mysql連接的3種方法總結(jié)

    Java中如何獲取mysql連接的3種方法總結(jié)

    最近工作中需要用到mysql連接,發(fā)現(xiàn)實(shí)現(xiàn)的方法不止一個(gè),所以就來(lái)總結(jié)下,下面這篇文章主要給大家介紹了關(guān)于Java中如何獲取mysql連接的3種方法,需要的朋友可以參考借鑒,感興趣的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-08-08
  • 深入學(xué)習(xí)java并發(fā)包ConcurrentHashMap源碼

    深入學(xué)習(xí)java并發(fā)包ConcurrentHashMap源碼

    這篇文章主要介紹了深入學(xué)習(xí)java并發(fā)包ConcurrentHashMap源碼,整個(gè) ConcurrentHashMap 由一個(gè)個(gè) Segment 組成,Segment 代表”部分“或”一段“的意思,所以很多地方都會(huì)將其描述為分段鎖。,需要的朋友可以參考下
    2019-06-06
  • JAVA中string數(shù)據(jù)類(lèi)型轉(zhuǎn)換詳解

    JAVA中string數(shù)據(jù)類(lèi)型轉(zhuǎn)換詳解

    在JAVA中string是final類(lèi),提供字符串不可以修改,string類(lèi)型在項(xiàng)目中經(jīng)常使用,下面給大家介紹了string七種數(shù)據(jù)類(lèi)型轉(zhuǎn)換,需要的朋友可以參考下
    2015-07-07
  • SpringBoot 定制化返回?cái)?shù)據(jù)的實(shí)現(xiàn)示例

    SpringBoot 定制化返回?cái)?shù)據(jù)的實(shí)現(xiàn)示例

    這篇文章主要介紹了SpringBoot 定制化返回?cái)?shù)據(jù)的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07

最新評(píng)論