思考一個對象在jvm是如何溜達的

先前有個問題待解決,“一個對象在jvm 是如何存在的”, 今天花時間在這里總結(jié)一下。

  1. 類加載, 在方法區(qū)中, class類型, 靜態(tài)變量 所有線程共享
    一個對象創(chuàng)建之前,會檢查對應(yīng)的class類型是否已經(jīng)加載進來,沒有,一般經(jīng)過類的加載機制,
    雙親委派模式進行加載,將Class類加載進方法區(qū)中,class文件的版本,字段,方法等類描述信息,
    還要靜態(tài)變量,常量。

  2. 常量池, 符號引用, 字面量, 所有線程共享
    class文件中存在一些符號引用和字面量,這些信息存儲到方法區(qū)里面的常量池

  3. 堆heap, 對象的創(chuàng)建, 所有線程共享
    對象的創(chuàng)建,根據(jù)class類,利用構(gòu)造函數(shù)進行創(chuàng)建對象,首先在heap堆中分配內(nèi)存,
    這個對象是所有線程共享。 對象所需的內(nèi)存大小在類加載完成后便可確定,
    為對象分配空間的任務(wù)等同于把一塊確定大小的內(nèi)存從 Java 堆中劃分出來。

3.1. 分配方式有 “指針碰撞” 和 “空閑列表” 兩種,選擇那種分配方式由 Java 堆是否規(guī)整決定,
而Java堆是否規(guī)整又由所采用的垃圾收集器是否帶有壓縮整理功能決定。

-   指針碰撞
 Java 堆內(nèi)存規(guī)整,GC 收集器的算法采用了復(fù)制算法,標(biāo)記-整理算法
-   空閑列表
Java 堆內(nèi)存不規(guī)整,GC 收集器的算法采用了標(biāo)記-清除算法

```
堆一般是垃圾收集器管理的主要區(qū)域, 一般分為 新生代與老年代,perm持久代
新生代分為Eden區(qū), from survivor(s1), to survivor(s2),
一般創(chuàng)建的對象在eden區(qū),當(dāng)eden的空間滿了,發(fā)生minor gc,
就是將eden區(qū)存活對象通過標(biāo)記-整理算法(或者其他算法)移動到s0區(qū),同時記錄對象的存活次數(shù)。
然后eden區(qū)清空了,沒有對象,為下次創(chuàng)建對象做準(zhǔn)備。
然后新的創(chuàng)建的對象又在eden區(qū),eden區(qū)又滿了,此時會發(fā)生minor gc, 然后呢,將eden區(qū)存活的對象,
和s0區(qū)存活的對象通過gc算法(復(fù)制,標(biāo)記-整理)移動到s1區(qū),同時記錄對象存活的次數(shù)。

如此反復(fù),當(dāng)存活的對象的次數(shù)大于系統(tǒng)設(shè)置的閾值,此時會在發(fā)生minor GC的時候,將對象移動到老年代中。
當(dāng)老年代的空間也滿了,此時會發(fā)生full GC, 會將所有區(qū)間無引用的對象清除

持久代在方法區(qū)method area, 這里存儲了類的描述信息,常量與符號引用

```

3.2. 為對象的屬性初始化零值
內(nèi)存分配完成后,虛擬機需要將分配到的內(nèi)存空間都初始化為零值(不包括對象頭),這一步操作保證了對象的實例字段在 Java 代碼中可以不賦初始值就直接使用,

3.3. 設(shè)置對象頭
初始化零值完成之后,虛擬機要對對象進行必要的設(shè)置,例如這個對象是那個類的實例、
如何才能找到類的元數(shù)據(jù)信息、對象的哈希嗎、對象的 GC 分代年齡等信息。
這些信息存放在對象頭中。

3.4. 執(zhí)行 init 方法
執(zhí)行對象的init方法,比如{}

  1. 創(chuàng)建類型的變量, 棧
    在棧里,一個線程創(chuàng)建對應(yīng)類型的變量,同時會將對象的內(nèi)存地址指向變量,在線程棧內(nèi),對象的其他屬性值會從
    堆中拷貝一份到線程棧中,線程自己定義的屬性會在自己的線程棧中。

  2. 調(diào)用方法, 棧
    通過類型變量(引用)調(diào)用方法,此時會在棧中創(chuàng)建本地方法幀,在方法幀中定義的local variable局部變量,在方法幀(棧)
    中,通過參數(shù)傳遞進來的,會從堆中拷貝一份到方法幀中,這里涉及到傳值還是傳址。

  3. 調(diào)用的過程中,會使用到程序計數(shù)器,程序計數(shù)器處理記錄指令,分支,循環(huán),跳轉(zhuǎn),異常之類的情況。

  4. 方法調(diào)用之后,會將對應(yīng)的數(shù)據(jù)與引用釋放,此時對象的應(yīng)用釋放了。
    當(dāng)遇到minor GC 時, 會將無引用的對象清除。無引用的對象指的是,該對象沒有指向,該對象的屬性沒有其他引用。

  5. 該對象如果沒有被清除,且該計數(shù)值大于閾值,會進入老年代中。
    最后的最后, 該對象最終會被清除的。

  6. 如果該對象調(diào)用了本地方法,native方法, 會在本地方法棧中分配內(nèi)存進行調(diào)用本地方法

  7. 當(dāng)所有對象實例被回收,對應(yīng)的類加載器classloader被回收, class對象沒有對應(yīng)的反射,
    這些條件都滿足時,此時會在持久代(method area)進行回收class類信息。

appendix

  1. 什么是符號引用?
    符號引用拆開來看,先需要符號,然后查找對應(yīng)的符號引用關(guān)系,在jvm中,class文件會轉(zhuǎn)換成一堆堆
    指令,一條指令存在引用其他符號的情況,比如invokevirtual #2, 會到常量池中尋找對應(yīng)的符號。

  2. 直接引用
    符號引用在jvm運行時,會轉(zhuǎn)換成直接引用, 直接引用是可以在運行時直接調(diào)用,比如方法調(diào)用,
    運行轉(zhuǎn)換成直接引用,這個方法需要到虛方法表中查找。

refrence

PS: 若你覺得可以、還行、過得去、甚至不太差的話,可以“關(guān)注”一下,就此謝過!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容