日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

JVM - 写了这么多年代码,你还不知道new对象背后的逻辑?

發(fā)布時(shí)間:2025/3/21 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JVM - 写了这么多年代码,你还不知道new对象背后的逻辑? 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 對(duì)象創(chuàng)建流程
    • 【類(lèi)加載檢查】
    • 【分配內(nèi)存】
      • 內(nèi)存劃分的兩種方式
      • 解決分配內(nèi)存并發(fā)問(wèn)題的兩種方式
    • 【初始化】
    • 【設(shè)置對(duì)象頭】
      • 對(duì)象的組成
      • 對(duì)象頭的兩部分組成
    • 【執(zhí)行init方法】
  • 總結(jié)一下

對(duì)象創(chuàng)建流程

我們知道JVM三大組成部分: 類(lèi)加載子系統(tǒng)、運(yùn)行時(shí)數(shù)據(jù)區(qū) 、字節(jié)碼執(zhí)行引擎。

要想new 一個(gè)對(duì)象,肯定是要繞不開(kāi)JVM的機(jī)制。

【類(lèi)加載檢查】

JVM啟動(dòng)的時(shí)候并不是將所有的類(lèi)都初始化,所以當(dāng)碰到一個(gè)new指令時(shí),JVM首先會(huì)去檢查這個(gè)類(lèi)有沒(méi)有被加載,具體就是去常量池中看是否有這個(gè)類(lèi)的符號(hào)引用,并檢查這個(gè)符號(hào)引用代表的類(lèi)是否已經(jīng)被加載、解析和初始化過(guò) 。 若沒(méi)有這必須經(jīng)歷【類(lèi)加載子系統(tǒng)】的歷練 (加載–校驗(yàn)–準(zhǔn)備–解析–初始化)

JVM-白話聊一聊JVM類(lèi)加載和雙親委派機(jī)制源碼解析


【分配內(nèi)存】

類(lèi)加載校驗(yàn)通過(guò)后 ,是不是該分配內(nèi)存了呢?

是的, 接下來(lái)JVM將會(huì)為這個(gè)新生的對(duì)象分給內(nèi)存,因?yàn)檫@個(gè)新生對(duì)象所需要內(nèi)存大小在類(lèi)加載完之后便可以完全確定,對(duì)象放哪里呢? 通常都是放在堆中,所以所謂的分配內(nèi)存實(shí)際上就是從Java堆中劃分出一塊固定大小的內(nèi)存給這個(gè)新生對(duì)象。

雖然很簡(jiǎn)單的一件事情,但是要考慮的地方可不少

  • 采取何種方式分配內(nèi)存
  • 并發(fā)問(wèn)題
  • 內(nèi)存劃分的兩種方式

    JVM提供了2中劃分內(nèi)存的方法

    • 指針碰撞(Bump the Pointer) 【默認(rèn)方式

    如果堆中的內(nèi)存是絕對(duì)規(guī)整的,大家都按順序排放,分配過(guò)內(nèi)存的對(duì)象那個(gè)在一邊,未使用的內(nèi)存在另外一邊 ,分界線使用指針來(lái)維護(hù)。因?yàn)樾律鷮?duì)象所需要內(nèi)存大小在類(lèi)加載完之后便可以完全確定,所以僅需要將指針移動(dòng)對(duì)象大小的位置即可。

    當(dāng)然了這是一種理想的情況,JVM里還有GC,會(huì)標(biāo)記清除等等

    • 空閑列表(Free List)

      如果堆內(nèi)存中的內(nèi)存并不是規(guī)整的,分配的內(nèi)存和未分配的內(nèi)存糅雜在一起, 如果還用上面的指針碰撞的方式, 如果移動(dòng)的可用內(nèi)存無(wú)法容納這個(gè)對(duì)象,放不下啊? 咋弄? 繼續(xù)碰么?

    顯然效率很低。 所以JVM采用了另外一種方式,JVM維護(hù)了一個(gè)列表,記錄了堆中的可用內(nèi)存,那么分配內(nèi)存的時(shí)候就從JVM維護(hù)的列表中找一個(gè)足夠容納這個(gè)對(duì)象的內(nèi)存區(qū)域給它,并更新列表記錄。


    解決分配內(nèi)存并發(fā)問(wèn)題的兩種方式

    第二個(gè)問(wèn)題 并發(fā)問(wèn)題如何解決呢?

    在并發(fā)的情況下,可能出現(xiàn)JVM正在給對(duì)象A分配內(nèi)存,但是指針還沒(méi)來(lái)得及修改,對(duì)象B又使用了A的內(nèi)存空間的情況。

    為了解決這個(gè)問(wèn)題,JVM采取了

    • CAS (compare and swap)

    簡(jiǎn)而言之就是JVM采用【 CAS+失敗重試 】保證更新操作的原子性 。

    • 本地線程分配緩沖 (Thread Local Allocation Buffer , TLAB)

    把內(nèi)存分配的動(dòng)作按照線程劃分在不同的空間之中進(jìn)行,即每個(gè)線程在Java堆中預(yù)先分配一小塊內(nèi)存

    通過(guò)-XX:+/- UseTLAB參數(shù)來(lái)設(shè)定虛擬機(jī)是否使用TLAB。

    JDK8中默認(rèn)開(kāi)啟XX:+UseTLAB ,默認(rèn)值eden區(qū)域的1%,當(dāng)然了也可以通過(guò)-XX:TLABSize 指定TLAB大小 。 一般不建議修改。

    如果TLAB還放不下,那就走CAS了…

    不管怎么分配,目的只是為了更好的回收內(nèi)存或者更快的分配對(duì)象


    【初始化】

    內(nèi)存分配完成后,虛擬機(jī)需要將分配到的內(nèi)存空間都初始化為零值(不包括對(duì)象頭).

    如果使用TLAB,這一工作過(guò)程也可以提前至TLAB分配時(shí)進(jìn)行。

    這一步操作保證了對(duì)象的實(shí)例字段在Java代碼中可以不賦初始值就直接使用,程序能訪問(wèn)到這些字段的數(shù)據(jù)類(lèi)型所對(duì)應(yīng)的默認(rèn)值 (比如 int 默認(rèn)0 , String 默認(rèn)null , boolean 默認(rèn)false等等)


    【設(shè)置對(duì)象頭】

    初始化默認(rèn)值以后,JVM要對(duì)對(duì)象進(jìn)行必要的設(shè)置,例如這個(gè)對(duì)象是哪個(gè)類(lèi)的實(shí)例、如何才能找到類(lèi)的元數(shù)據(jù)信息、對(duì)象的哈希碼、對(duì)象的GC分代年齡等信息。這些信息存放在對(duì)象的對(duì)象頭Object Header之中。

    這部分?jǐn)?shù)據(jù)的長(zhǎng)度在32位和64位的虛擬機(jī)中分別為32個(gè)和64個(gè)bits,官方稱(chēng)它為“Mark Word”。


    對(duì)象的組成

    在HotSpot虛擬機(jī)中,對(duì)象在內(nèi)存中存儲(chǔ)的布局可以分為3塊區(qū)域:對(duì)象頭(Header)、 實(shí)例數(shù)據(jù)(Instance Data)和和對(duì)齊填充(Padding) 。


    對(duì)象頭的兩部分組成

    HotSpot虛擬機(jī)的對(duì)象頭包括兩部分信息

    • 第一部分用于存儲(chǔ)對(duì)象自身的運(yùn)行時(shí)數(shù)據(jù), 如哈希碼(HashCode)、GC分代年齡、鎖狀態(tài)標(biāo)志、線程持有的鎖、偏向線程ID、偏向時(shí) 間戳等。

    32位操作系統(tǒng)為例

    • 對(duì)象頭的另外一部分是類(lèi)型指針,即對(duì)象指向它的類(lèi)元數(shù)據(jù)的指針,虛擬機(jī)通過(guò)這個(gè)指針來(lái)確定這個(gè)對(duì)象是哪個(gè)類(lèi)的實(shí)例。

    如下所示


    【執(zhí)行init方法】

    執(zhí)行方法,即對(duì)象按照程序員的意愿進(jìn)行初始化。對(duì)應(yīng)到語(yǔ)言層面上講,就是為屬性賦值(注意,這與上面的賦零值不同,這是由程序員賦的值) 和執(zhí)行構(gòu)造方法。

    IDEA安裝jclasslib插件可以查看

    這里的init實(shí)際上是C++調(diào)用的,相對(duì)于面向開(kāi)發(fā)人員 就是 new Artisan() ,并執(zhí)行Artisan默認(rèn)的構(gòu)造函數(shù)。



    總結(jié)一下


    總結(jié)

    以上是生活随笔為你收集整理的JVM - 写了这么多年代码,你还不知道new对象背后的逻辑?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。