最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java對(duì)象創(chuàng)建的過程流程分析

 更新時(shí)間:2026年01月10日 15:46:30   作者:栗子葉  
本文詳細(xì)介紹了Java對(duì)象創(chuàng)建的整個(gè)過程,包括類加載、內(nèi)存分配、對(duì)象頭設(shè)置、構(gòu)造器初始化以及內(nèi)存分配的安全問題,文章還討論了新生代和老年代的內(nèi)存分配策略,特別是使用指針碰撞和空閑列表兩種方式,感興趣的朋友跟隨小編一起看看吧

一、類加載過程

  1. 類加載檢查
    • 當(dāng)Java虛擬機(jī)(JVM)遇到new關(guān)鍵字時(shí),它會(huì)先檢查要?jiǎng)?chuàng)建的對(duì)象類是否已經(jīng)被加載、鏈接和初始化。如果尚未加載,JVM會(huì)通過類加載器(ClassLoader)加載對(duì)應(yīng)類的.class文件。
  2. 類加載
    • 類加載包括三個(gè)子步驟:加載、連接、初始化。
      • 加載:通過權(quán)限定類名,讀取 class 文件內(nèi)容為二進(jìn)制流;二進(jìn)制流轉(zhuǎn)換成方法區(qū)(永久代或元數(shù)據(jù)區(qū))的運(yùn)行時(shí) C++類字節(jié)碼對(duì)象 Klass;最后再在堆上生成一個(gè) Class 對(duì)象,用來間接獲取元數(shù)據(jù)區(qū)的類定義信息,靜態(tài)對(duì)象也保存在 Class 對(duì)象中。
      • 連接
        • **驗(yàn)證:**驗(yàn)證文件格式、字節(jié)碼元數(shù)據(jù)、語法、符號(hào)引用;
        • 準(zhǔn)備:為類的靜態(tài)變量分配內(nèi)存,并賦予默認(rèn)初始值(例如0或null),但不會(huì)執(zhí)行任何實(shí)際的初始化代碼。
        • **解析:**將符號(hào)引用替換為直接引用。
      • 初始化:類的靜態(tài)變量賦予正確的初始值,執(zhí)行靜態(tài)塊;可能涉及父類初始化。
  3. 內(nèi)存分配
    • JVM為新創(chuàng)建的對(duì)象分配內(nèi)存空間。對(duì)象內(nèi)存主要包括對(duì)象頭、實(shí)例數(shù)據(jù)以及可能的對(duì)齊填充。
      • 對(duì)象頭:存儲(chǔ)對(duì)象自身的元數(shù)據(jù)如哈希碼、鎖狀態(tài)標(biāo)志、GC分代年齡等信息,以及指向其類元數(shù)據(jù)(Class對(duì)象)的指針。
      • 實(shí)例數(shù)據(jù):存儲(chǔ)類中定義的字段的實(shí)際數(shù)據(jù)。
      • 對(duì)齊填充:非必須,為了滿足JVM對(duì)內(nèi)存地址對(duì)其的要求而填充的額外空間。
  4. 初始化零值
    • 分配內(nèi)存后,JVM會(huì)對(duì)對(duì)象的所有字段(包括實(shí)例變量)分配默認(rèn)的初始值。
  5. 顯式初始化:接下來,如果有在字段聲明時(shí)直接賦予的初始值(例如int a = 10;),這些值會(huì)在構(gòu)造函數(shù)執(zhí)行前被賦予相應(yīng)的變量。
  6. **對(duì)象頭 必要信息設(shè)置 **主要是對(duì)象頭中類的源數(shù)據(jù)信息,哈希碼 ,對(duì)象 GC 分代年齡等。
  7. 初始化
    • 構(gòu)造器初始化:調(diào)用類的構(gòu)造方法(即構(gòu)造器)進(jìn)行初始化,執(zhí)行構(gòu)造器中的初始化代碼,此時(shí)才會(huì)給實(shí)例變量賦予程序員指定的初始值。
    • 如果類中有父類并且還沒有被初始化,則先初始化父類。
  8. 對(duì)象構(gòu)造完成
    • 構(gòu)造方法執(zhí)行完畢后,對(duì)象就完全構(gòu)造出來了,可以被程序正常使用。

二、對(duì)象內(nèi)存分配方式

內(nèi)存分配方式根據(jù)不同的收集器策略可分為兩種,不同的收集器的堆內(nèi)存規(guī)整程度不一致所以有兩種分配策略。

指針碰撞 Bump The Pointer

在使用指針碰撞策略時(shí),Java堆被假設(shè)為一個(gè)連續(xù)的內(nèi)存空間,被分為已用和未用兩部分,中間由一個(gè)指針作為分界線。當(dāng)新對(duì)象需要內(nèi)存時(shí),JVM只需將指針向未用空間一側(cè)移動(dòng)與對(duì)象大小相等的距離即可。這種方式適用于使用標(biāo)記-清除復(fù)制算法的垃圾收集器,因?yàn)檫@些算法能夠整理出連續(xù)的內(nèi)存空間。

空閑列表 Free List

如果Java堆中的內(nèi)存不是連續(xù)的,或者已被使用的內(nèi)存和未被使用的內(nèi)存相互交錯(cuò)(這種情況通常發(fā)生在使用標(biāo)記-整理或分代收集算法的垃圾收集器中),那么空閑列表策略更為適用。在這種情況下,JVM維護(hù)一個(gè)列表來記錄堆中各個(gè)小塊的可用內(nèi)存空間。當(dāng)新對(duì)象需要內(nèi)存時(shí),JVM會(huì)從列表中找到一個(gè)足夠大的空閑塊分配給對(duì)象,并更新列表。這種方法不需要連續(xù)的內(nèi)存空間,但管理成本相對(duì)較高。

三、內(nèi)存分配的安全問題

堆是線程間共享的一塊兒區(qū)域,所以多個(gè)線程同時(shí)創(chuàng)建對(duì)象時(shí)都涉及對(duì)內(nèi)存空間的申請(qǐng)和分配,那么內(nèi)存分配就可能出現(xiàn)線程安全問題。依賴以下機(jī)制解決多線程安全問題,一種是** CAS 樂觀鎖機(jī)制**,一種是 TLAB 本地線程分配緩沖機(jī)制

Thread Local Allocation Buffer (TLAB) 本地線程分配緩沖:每個(gè)線程有一個(gè)屬于自己的預(yù)分配內(nèi)存空間,JVM 首先通過 CAS 為線程申請(qǐng)一塊兒預(yù)分配內(nèi)存。這樣當(dāng)某個(gè)線程需要申請(qǐng)新的內(nèi)存空間時(shí)首先現(xiàn)在自己的 TLAB 上分配,能減少內(nèi)存分配沖突。后續(xù) TLAB 內(nèi)存不足了才會(huì) CAS 申請(qǐng)一塊兒新的 LATB 或者直接在 Eden 區(qū)直接分配。

Compare-and-Swap (CAS) 在某些JVM實(shí)現(xiàn)中,可能會(huì)使用CAS操作來實(shí)現(xiàn)無鎖的線程安全內(nèi)存分配。CAS是一種硬件級(jí)別的原子操作,允許線程在不加鎖的情況下比較并交換內(nèi)存中的值,從而減少鎖帶來的性能開銷,并能有效防止數(shù)據(jù)競(jìng)爭。

四、對(duì)象如何進(jìn)入老年代

  1. 新生代:剛創(chuàng)建的對(duì)象默認(rèn)進(jìn)入新生代的 Eden 區(qū)
  2. 進(jìn)入老年代的條件:四種情況
    1. 熬過了多次 minorGC ,每次 MinorGC 過后對(duì)象的年齡就會(huì)+1,存活超過 15 次之后就會(huì)進(jìn)入老年代。該次數(shù)可通過參數(shù)控制 -XX:MaxTenuringThreshold
    2. 動(dòng)態(tài)年齡判斷機(jī)制:MinorGC 后,如果 Survivor 區(qū)中的一批對(duì)象大雨了這塊 Survivor 區(qū)的 50%就會(huì)將大于等于這批對(duì)象年齡最大值的所有對(duì)象直接進(jìn)入老年代。
      1. 舉例 S1 中有 年齡為 1 、2、3、4 的一批對(duì)象,其中 234 年齡的加起來超過 S1 的 50%,那么年齡大于等于 4 的對(duì)象就直接進(jìn)入老年代了。
    3. Serial 和 ParNew 收集器,大對(duì)象直接進(jìn)入老年代。例如大字符串和數(shù)組 可通過-XX:PertenureSizeThreshold 配置 默認(rèn)為 1M
    4. MinorGC 后,存活的對(duì)象太多無法放入 Sruvivor 區(qū)域,會(huì)觸發(fā)空間分配擔(dān)保機(jī)制。將存活的對(duì)象移入老年代

分配擔(dān)保機(jī)制(空間擔(dān)保) Allocation Assurance Mechanism

什么是分配擔(dān)保機(jī)制

在 JVM 中,空間分配擔(dān)保機(jī)制(Space Allocation Guarantee Mechanism)是一種確保在進(jìn)行垃圾收集時(shí),有足夠的空間來處理對(duì)象晉升分配的策略。這種機(jī)制主要用于新生代垃圾收集(Minor GC)和老年代垃圾收集(Major GC 或 Full GC)之間的協(xié)調(diào),以避免出現(xiàn)內(nèi)存不足的情況。

:::success
用老年代的空間,來擔(dān)保新生代的垃圾回收可以成功執(zhí)行并騰出空間。會(huì)將新生代存活的對(duì)象轉(zhuǎn)移到老年代中。保證新分配內(nèi)存能直接成功。

  1. young 分區(qū)內(nèi)存不足以創(chuàng)建新對(duì)象

:::

內(nèi)存擔(dān)保的原理

MinorGC前

  1. 第一步:判斷老年代可用內(nèi)存是否小于新時(shí)代對(duì)象全部對(duì)象大小,如果小于則繼續(xù)判斷,大于則可進(jìn)行MainorGC
  2. 第二步:老年代小于存活對(duì)象,則判斷老年代內(nèi)存是否小于每次MinorGC后進(jìn)入老年代的平均大小
    1. 小于平均大小,則進(jìn)行FullGC,再判斷是否能保存得下存活對(duì)象,放不下則OOM
    2. 大于平均大小,則進(jìn)行MinorGC

MinorGC后

  1. 如果存活對(duì)象小于Survivor區(qū),則直接進(jìn)入Survivor區(qū)
  2. 如果存活對(duì)象大于Survivor區(qū),但是小于老年代可用內(nèi)存,則直接進(jìn)入老年代
  3. 如果存活對(duì)象大于Survivor區(qū),還大于老年代,則嘗試進(jìn)行一次FullGC,F(xiàn)ullGC后再次判斷,如果放不下存活對(duì)象則會(huì)OOM

分配擔(dān)保的配置

  1. **-XX:HandlePromotionFailure:**這個(gè)參數(shù)控制是否允許晉升失敗。如果設(shè)置為 true,JVM 會(huì)在 Minor GC 時(shí)嘗試晉升對(duì)象,即使老年代空間不足,也會(huì)嘗試進(jìn)行一次 Minor GC。如果失敗,則觸發(fā) Full GC。這個(gè)參數(shù)在 Java 6 之后已經(jīng)被默認(rèn)取消使用。
  2. -XX:PretenureSizeThreshold:這個(gè)參數(shù)指定大對(duì)象直接在老年代分配的大小閾值。超過該閾值的對(duì)象直接分配到老年代,避免在新生代頻繁復(fù)制。
  3. **-XX:MaxTenuringThreshold:**這個(gè)參數(shù)控制對(duì)象在新生代中經(jīng)歷多少次 GC 后晉升到老年代。較高的閾值可以減少對(duì)象晉升,但會(huì)增加新生代的 GC 頻率。
  4. -XX:TargetSurvivorRatio:這個(gè)參數(shù)控制每次 Minor GC 后目標(biāo)存活區(qū)(Survivor Space)的利用率。JVM 會(huì)根據(jù)這個(gè)參數(shù)調(diào)整對(duì)象晉升的閾值。

五、驗(yàn)證

大對(duì)象直接進(jìn)入老年代

/**
* 測(cè)試:大對(duì)象直接進(jìn)入到老年代
* -Xmx60m -Xms60m -XX:NewRatio=2 -XX:SurvivorRatio=8 -XX:+PrintGCDetails
* -XX:PretenureSizeThreshold
*
*/
public class YoungOldArea {
    public static void main(String[] args) {
        byte[] buffer = new byte[1024*1024*20]; //20M
    }
}
-XX:NewRatio=2 新生代與老年代比值
-XX:SurvivorRatio=8 新生代中,Eden與兩個(gè)Survivor區(qū)域比值
-XX:+PrintGCDetails 打印詳細(xì)GC日志
-XX:PretenureSizeThreshold 對(duì)象超過多大直接在老年代分配,默認(rèn)值為0,不限制

對(duì)象內(nèi)存分代晉升演示

/*
-Xmx600m -Xms600m -XX:+PrintGCDetails
*/
public class HeapInstance {
  public static void main(String[] args) {
    List<Picture> list = new ArrayList<>();
    while (true){
      try {
        Thread.sleep(20);
     } catch (InterruptedException e) {
        e.printStackTrace();
     }
      list.add(new Picture(new Random().nextInt(1024 * 1024)));
   }
 }
}
class Picture{
  private byte[] pixels;
  public Picture(int length){
    this.pixels = new byte[length];
 }
}

通過可視化插件可以看到

  1. Eden區(qū)滿了之后,就會(huì)進(jìn)行MinorGC,MinorGC時(shí)會(huì)將Survior放不下的對(duì)象存到old老年代
  2. 老年代也滿了之后,發(fā)生了三次MinorGC,未釋放出可用空間后,進(jìn)行了三次FullGc最后拋出了OOM

到此這篇關(guān)于Java對(duì)象創(chuàng)建的過程的文章就介紹到這了,更多相關(guān)Java對(duì)象創(chuàng)建內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JAVA字符串占位符使用方法實(shí)例

    JAVA字符串占位符使用方法實(shí)例

    今天同事又問起類似符串占位符使用的功能,所以下面這篇文章主要給大家介紹了關(guān)于JAVA字符串占位符使用的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-11-11
  • hotspot解析jdk1.8?Unsafe類park和unpark方法使用

    hotspot解析jdk1.8?Unsafe類park和unpark方法使用

    這篇文章主要為大家介紹了hotspot解析jdk1.8?Unsafe類park和unpark方法使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • Java中DTO與Entity拷貝轉(zhuǎn)換的方法小結(jié)

    Java中DTO與Entity拷貝轉(zhuǎn)換的方法小結(jié)

    在?Java?開發(fā)中,DTO(Data?Transfer?Object)和?Entity(實(shí)體類)是常見的兩種數(shù)據(jù)模型,本文將介紹幾種常見的工具類和自定義方式來實(shí)現(xiàn)這種轉(zhuǎn)換,感興趣的可以了解下
    2025-02-02
  • spring validation多層對(duì)象校驗(yàn)教程

    spring validation多層對(duì)象校驗(yàn)教程

    這篇文章主要介紹了spring validation多層對(duì)象校驗(yàn)教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • 關(guān)于easyExcel中讀取Excel表頭的實(shí)例說明

    關(guān)于easyExcel中讀取Excel表頭的實(shí)例說明

    EasyExcel是阿里巴巴開源的一個(gè)excel處理框架,以使用簡單、節(jié)省內(nèi)存著稱,下面這篇文章主要給大家介紹了關(guān)于easyExcel中讀取Excel表頭的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • Java數(shù)據(jù)結(jié)構(gòu)之環(huán)形鏈表和約瑟夫問題詳解

    Java數(shù)據(jù)結(jié)構(gòu)之環(huán)形鏈表和約瑟夫問題詳解

    約瑟夫(Josephus)問題是單向環(huán)形鏈表的一種體現(xiàn),也就是丟手帕問題,下面這篇文章主要給大家介紹了關(guān)于Java數(shù)據(jù)結(jié)構(gòu)之環(huán)形鏈表和約瑟夫問題的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-08-08
  • Java線程的調(diào)度與優(yōu)先級(jí)詳解

    Java線程的調(diào)度與優(yōu)先級(jí)詳解

    這篇文章主要為大家詳細(xì)介紹了Java線程的調(diào)度與優(yōu)先級(jí),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • springboot集成flowable實(shí)踐

    springboot集成flowable實(shí)踐

    本文介紹了Flowable業(yè)務(wù)流程管理引擎在Spring Boot 2.3版本中的集成,Flowable支持BPMN2.0標(biāo)準(zhǔn),提供了流程定義、實(shí)例管理和數(shù)據(jù)訪問等功能,文章詳細(xì)介紹了Flowable生成的數(shù)據(jù)庫表及其用途,并通過一個(gè)請(qǐng)假審批流程的示例,展示了如何部署和測(cè)試Flowable
    2026-01-01
  • 詳解Java中hashCode的作用

    詳解Java中hashCode的作用

    這篇文章主要介紹了詳解Java中hashCode的作用的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Java面試Socket編程常用參數(shù)設(shè)置源碼問題分析

    Java面試Socket編程常用參數(shù)設(shè)置源碼問題分析

    這篇文章主要為大家介紹了Java編程中關(guān)于Socket結(jié)構(gòu)分析,常用參數(shù)設(shè)置源碼示例以及面試中的問題分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2022-03-03

最新評(píng)論

武定县| 淅川县| 平顺县| 苍山县| 楚雄市| 应用必备| 白水县| 望江县| 滕州市| 萍乡市| 和政县| 瑞丽市| 宝清县| 和田市| 岱山县| 叙永县| 定西市| 扎赉特旗| 庄浪县| 东乌珠穆沁旗| 芷江| 高淳县| 年辖:市辖区| 门头沟区| 辽阳市| 莲花县| 定远县| 宁国市| 乌恰县| 阳春市| 曲阜市| 滦南县| 厦门市| 台安县| 吴川市| 新野县| 洛隆县| 双牌县| 彰化市| 怀仁县| 大关县|