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

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

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

一、類加載過程

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

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

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

指針碰撞 Bump The Pointer

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

空閑列表 Free List

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

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

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

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

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

四、對象如何進入老年代

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

分配擔保機制(空間擔保) Allocation Assurance Mechanism

什么是分配擔保機制

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

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

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

:::

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

MinorGC前

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

MinorGC后

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

分配擔保的配置

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

五、驗證

大對象直接進入老年代

/**
* 測試:大對象直接進入到老年代
* -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與兩個Survivor區(qū)域比值
-XX:+PrintGCDetails 打印詳細GC日志
-XX:PretenureSizeThreshold 對象超過多大直接在老年代分配,默認值為0,不限制

對象內(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ū)滿了之后,就會進行MinorGC,MinorGC時會將Survior放不下的對象存到old老年代
  2. 老年代也滿了之后,發(fā)生了三次MinorGC,未釋放出可用空間后,進行了三次FullGc最后拋出了OOM

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

相關文章

  • JAVA字符串占位符使用方法實例

    JAVA字符串占位符使用方法實例

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

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

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

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

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

    spring validation多層對象校驗教程

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

    關于easyExcel中讀取Excel表頭的實例說明

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

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

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

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

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

    springboot集成flowable實踐

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

    詳解Java中hashCode的作用

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

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

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

最新評論

汕尾市| 阜城县| 云梦县| 思南县| 惠州市| 休宁县| 新宾| 廉江市| 报价| 襄城县| 武功县| 南安市| 咸宁市| 太保市| 张家港市| 上高县| 长岛县| 新干县| 安阳县| 曲松县| 台湾省| 文安县| 石河子市| 界首市| 翁牛特旗| 抚松县| 宜兰县| 堆龙德庆县| 双江| 昌乐县| 广灵县| 台湾省| 博白县| 辽阳市| 安康市| 白水县| 南漳县| 宝丰县| 塔城市| 永春县| 来凤县|