AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當前位置:首頁 > 科技  > 軟件

原來New關鍵字創建對象的背后還隱藏了這么多秘密,看完這篇文章我頓悟了

來源: 責編: 時間:2023-11-30 09:29:38 280觀看
導讀前言對于前面幾篇文章, 主要就是說明了一個.java文件是如何一步步編譯, 解析最后加載到JVM中運行的, 那么本篇文章將說明對象是如何創建的, 包括創建過程、對象頭與指針壓縮、jvm對象內存分配詳解、逃逸分析,線上分配,

前言

對于前面幾篇文章, 主要就是說明了一個.java文件是如何一步步編譯, 解析最后加載到JVM中運行的, 那么本篇文章將說明對象是如何創建的, 包括創建過程、對象頭與指針壓縮、jvm對象內存分配詳解、逃逸分析,線上分配,標量替換等等內容。EAc28資訊網——每日最新資訊28at.com

內容有點多,所以準備分為三篇文章來寫:EAc28資訊網——每日最新資訊28at.com

  • JVM對象創建及對象大小與指針壓縮
  • 對象內存分配
  • 對象內存回收

如果感覺文章中有的圖片字太小不清楚的可以通過公眾號加我,然后說明是哪篇文章的圖片,然后我發給你。EAc28資訊網——每日最新資訊28at.com

對象的創建

對象創建的主要流程:EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

1.類加載檢查

虛擬機遇到一條new指令時,首先將去檢查這個指令的參數是否能在常量池中定位到一個類的符號引用,并且檢查這個符號引用代表的類是否已被加載、解析和初始化過。如果沒有,那必須先執行相應的類加載過程。new指令對應到語言層面上講是,new關鍵詞、對象克隆、對象序列化等。EAc28資訊網——每日最新資訊28at.com

對于我們來說,我們寫的java代碼是new 一個對象,實際上對于底層jvm實際上是執行了一個new 指令。EAc28資訊網——每日最新資訊28at.com

這里用的插件是:jclasslib Bytecode ViewerEAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

首先會判斷這個類有沒有被加載過,如果沒有加載過,那么它首先會執行加載類的過程(前幾篇文章有講),如果加載過了,那么就要開始new對象了,這個對象一般來說可能放在堆中也有可能放在棧里邊,但是不管放在哪,前提都是需要分配一塊內存空間的。EAc28資訊網——每日最新資訊28at.com

2.分配內存

在類加載檢查通過后,接下來虛擬機將為新生對象分配內存。對象所需內存的大小在類 加載完成后便可完全確定,為對象分配空間的任務等同于把 一塊確定大小的內存從Java堆中劃分出來。EAc28資訊網——每日最新資訊28at.com

這個步驟有兩個問題:EAc28資訊網——每日最新資訊28at.com

  • 如何劃分內存。
  • 在并發情況下, 可能出現正在給對象A分配內存,指針還沒來得及修改,對象B又同時使用了原來的指針來分配內存的情況。

劃分內存的方法:EAc28資訊網——每日最新資訊28at.com

“指針碰撞”(Bump the Pointer)(默認用指針碰撞)

如果Java堆中內存是絕對規整的,所有用過的內存都放在一邊,空閑的內存放在另一邊,中間放著一個指針作為分界點的指示器,比如下圖中藍色實線表示當前指針位置,虛線表示挪動后的位置,那所謂分配內存就僅僅是把那個指針向空閑空間那邊挪動一段與對象大小相等的距離。EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

“空閑列表”(Free List)

如果Java堆中的內存并不是規整的,已使用的內存和空 閑的內存相互交錯,那就沒有辦法簡單地進行指針碰撞了,虛擬機就必須維護一個列表,記錄上哪些內存塊是可用的,在分配的時候從列表中找到一塊足夠大的空間劃分給對象實例, 并更新列表上的記錄。EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

但是具體使用的是指針碰撞的方式還是使用的是空閑列表的分配方式,取決于使用的什么垃圾回收算法,如果使用的是標記整理的話,那么最終剩余的內存肯定是第一種,那么使用的也就是指針碰撞的方式,如果使用的是標記清除的話,那么最終剩余的內存肯定是第二種,所以就使用空閑列表的方式來分配內存。EAc28資訊網——每日最新資訊28at.com

解決并發問題的方法:EAc28資訊網——每日最新資訊28at.com

不管使用哪種方式分配,都會出現并發問題,也就是兩個線程同時創建了一個對象,然后爭搶同一塊內存EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

多個線程創建了多個對象,但是內存空間只有一塊,那么jvm為了解決這種并發問題,采取了以下兩種措施EAc28資訊網——每日最新資訊28at.com

CAS(compare and swap)

虛擬機采用CAS配上失敗重試的方式保證更新操作的原子性來對分配內存空間的動作進行同步處理。EAc28資訊網——每日最新資訊28at.com

CAS配上失敗重試也就是線程A和線程B同時爭搶這一塊內存,如果線程A先爭搶到了這塊內存,那么線程B重新進行分配,發現這塊內存分配給了線程A,然后就會在這塊內存后面進行內存分配操作。這樣線程A、B對象的內存空間就在并發的情況下被分配了。EAc28資訊網——每日最新資訊28at.com

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

把內存分配的動作按照線程劃分在不同的空間之中進行,即每個線程在Java堆中(比如Eden區)預先分配一小塊內存。通過-XX:+/-UseTLAB參數來設定虛擬機是否使用TLAB(JVM會默認開啟-XX:+UseTLAB)EAc28資訊網——每日最新資訊28at.com

那么這個內存也不可能特別大,好像默認是Eden區的1% , 通過-XX:TLABSize 可以指定TLAB大小。如果這個時候放不下了,那么就會恢復CAS配上失敗重試的方式進行分配。當然,一般不推薦你去改JVM默認的參數設置。EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

線程A和線程B在Eden區預先分配一塊屬于自己的內存空間,然后把各自的對象放到各自的空間種。JDK8默認使用的就是這種方式。EAc28資訊網——每日最新資訊28at.com

對象的分配過程會在下一篇文章詳細說明。EAc28資訊網——每日最新資訊28at.com

3.初始化零值

內存分配完成后,虛擬機需要將分配到的內存空間都初始化為零值(不包括對象頭), 如果使用TLAB,這一工作過程也可以提前至TLAB分配時進行。這一步操作保證了對象的實例字段在Java代碼中可以不賦初始值就直接使用,程序能訪問到這些字段的數據類型所對應的零值。EAc28資訊網——每日最新資訊28at.com

也就是對于對象的成員變量,比如int initData = 666;那么在這個過程,會先給initData 賦一個0值,就和前面有一篇文章中提到過靜態變量的初始化賦值是一樣的。最終可能有一步會把真正的值666賦給initData。EAc28資訊網——每日最新資訊28at.com

4.設置對象頭

初始化零值之后,虛擬機要對對象進行必要的設置,例如這個對象是哪個類的實例、如何才能找到類的元數據信息、對象的哈希碼、對象的GC分代年齡等信息。這些信息存放在對象的對象頭Object Header之中。EAc28資訊網——每日最新資訊28at.com

在HotSpot虛擬機中,對象在內存中存儲的布局可以分為3塊區域:對象頭(Header)、 實例數據(Instance Data)和對齊填充(Padding)。HotSpot虛擬機的對象頭包括兩部分信息,第一部分用于存儲對象自身的運行時數據, 如哈希碼(HashCode)、GC分代年齡、鎖狀態標志、線程持有的鎖、偏向線程ID、偏向時 間戳等。對象頭的另外一部分是類型指針,即對象指向它的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。EAc28資訊網——每日最新資訊28at.com

32位對象頭

圖片圖片EAc28資訊網——每日最新資訊28at.com

對象頭中有一個Mark Word標記字段,第一列是對象的一個狀態,可能有一些對象被加鎖了或者是被GC標記了,不同的對象,它對象頭的結構是不一樣的,比如說一個對象是正常的對象,也就是沒有任何的鎖,對象頭中前面25bit存儲是對象的hashCode,中間4bit存儲的是對象的分代年齡,分代年齡在上一篇文章中有講過,它是4bit,也就以為著它的分代年齡是<=15的,因為4位(bit)大小可以表示從0到15的數值,因此無法存儲大于15的數值,當然還有一些偏向鎖、鎖標志位等鎖的標記。關于鎖的相關內容也會在后面寫并發相關的文章的時候進行詳解。EAc28資訊網——每日最新資訊28at.com

還有一塊就是Klass Pointer類型指針,一個對象new出來之后是放到堆中的,但是在這個對象的頭部區域,有一個指針,指向方法區的對象所屬的類的元數據信息。如下圖中畫紅線的地方的示例。EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

比如說就是下面這一段代碼,要想在元數據區找到compute方法對應的代碼,就是通過這個類型指針Klass Pointer去找。EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

那么還有一個對象叫做類對象,比如Math類所屬的對象mathClass,這個對象是放在堆中的。EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

堆中的這個mathClass對象和元數據區的Math.class是什么關系呢?            EAc28資訊網——每日最新資訊28at.com

Math.class是類的元數據信息,也就是我們編寫的代碼,那么mathClass是類裝載完之后,是jvm給我們開發人員在我們想訪問類的元數據信息是提供的一個對象,我們可以通過這個對象mathClass去訪問類的元數據信息,簡單一點就是反射,通過反射是可以獲取到很多信息的,類的名稱。方法的名稱等等。但是mathClass對象中是不會存儲這些代碼的,代碼只是存儲在方法區。EAc28資訊網——每日最新資訊28at.com

這個是jvm提供給我們開發人員去使用的,但是jvm內部不會這么干,而是通過剛剛講的類型指針。而元數據信息的存儲介質是C++對象,這個類型指針也是C++實現的。EAc28資訊網——每日最新資訊28at.com

還有一塊就是數組的長度,如果是一個數組對象的話,對象頭中還有一塊會存儲數組的長度。EAc28資訊網——每日最新資訊28at.com

64位對象頭

圖片圖片EAc28資訊網——每日最新資訊28at.com

對象頭在hotspot的C++源碼markOop.hpp文件里的注釋如下:EAc28資訊網——每日最新資訊28at.com

// Bit-format of an object header (most significant first, big endian layout below):////  32 bits://  --------//             hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)//             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)//             size:32 ------------------------------------------>| (CMS free block)//             PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)////  64 bits://  --------//  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)//  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)//  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)//  size:64 ----------------------------------------------------->| (CMS free block)////  unused:25 hash:31 -->| cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && normal object)//  JavaThread*:54 epoch:2 cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && biased object)//  narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)//  unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)

5.執行方法

執行方法,即對象按照程序員的意愿進行初始化。對應到語言層面上講,就是為屬性賦值(注意,這與上面的賦零值不同,這是由程序員賦的值),和執行構造方法。EAc28資訊網——每日最新資訊28at.com

這一步的話比如就會把initData賦值為666, 因為在初始化零值這個步驟中initData被賦值為0,這一步可以說是真正的進行賦值。也就是下圖中框起來的部分,這個過程是C++調用的。EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

對象大小與指針壓縮

對象大小可以用jol-core包查看,引入依賴EAc28資訊網——每日最新資訊28at.com

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

以下這幾行代碼的話主要就是想查看new Object() 以及new int[]{}還有new A()對象的大小。EAc28資訊網——每日最新資訊28at.com

package com.liuxs.fusionx;import org.openjdk.jol.info.ClassLayout;/** * @author: Liu Yuehui * @ClassName: JOLSample * @date: 2023/11/27 0:25 * @description: 查看對象大小 * @version:v1:2023/11/27 0:25: **/public class JOLSample {    public static void main(String[] args) {        ClassLayout layout = ClassLayout.parseInstance(new Object());        System.out.println(layout.toPrintable());        System.out.println();        ClassLayout layout1 = ClassLayout.parseInstance(new int[]{});        System.out.println(layout1.toPrintable());        System.out.println();        ClassLayout layout2 = ClassLayout.parseInstance(new A());        System.out.println(layout2.toPrintable());    }    // -XX:+UseCompressedOops           默認開啟的壓縮所有指針    // -XX:+UseCompressedClassPointers  默認開啟的壓縮對象頭里的類型指針Klass Pointer    // Oops : Ordinary Object Pointers    public static class A {        //8B mark word        //4B Klass Pointer   如果關閉壓縮-XX:-UseCompressedClassPointers或-XX:-UseCompressedOops,則占用8B        int id;        //4B        String name;   //4B  如果關閉壓縮-XX:-UseCompressedOops,則占用8B        byte b;        //1B        Object o;      //4B  如果關閉壓縮-XX:-UseCompressedOops,則占用8B    }}

運行結果:EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

Object對象大概是可以分為以下幾塊EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

這里的類型指針只占了4個字節是因為64位系統默認是8字節,但是會涉及到指針壓縮,壓縮之后就是4字節。EAc28資訊網——每日最新資訊28at.com

這里有一個叫對象對齊,也就是上面說到對象頭的第三塊對齊填充(Padding),這塊部分有的時候有,有的時候沒有,也就是jvm內部會把內存的讀取信息按照8個字節對齊,這個是整個jvm底層包括計算機組成原理經過大量實踐證明的,也就是通過8個字節的對象的對齊,會讓整個計算機的存取效率非常之高。EAc28資訊網——每日最新資訊28at.com

比如我這個操作系統是64位的,它的內存大概是一格一格的,比如下面這張圖,一共就是64位,現在有個對象只占一點空間,你在查這個對象的時候,還要評估這個對象的大小,然后從這個大小的起始位置去偏移,這就比較麻煩了,那么8個字節的存取說白了就是對象尋址最優的一種方式。EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

比如Object對象中,Mark Word標記字段和Klass pointer類型指針占了12字節,也就是這個Object對象真正的大小是12字節,但是為了滿足對象對齊是8的整數倍,所以有搞了4個字節的對齊,這樣就成了16字節,也就是8的2倍。讓我們對象總共的大小是16字節。EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

數組對象會多一個數組長度。EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

A對象

其它內容一樣,這里就不過多贅述了,這里的bate類型的b只占用了1字節,但是會有內部對齊,對齊成為了4字節,然后Object對象只占用了4字節,就是因為Object對象存儲的是指針,只占了4個字節是因為64位系統默認是8字節,但是會涉及到指針壓縮,壓縮之后就是4字節。EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

什么是Java對象的指針壓縮?

現象

圖片圖片EAc28資訊網——每日最新資訊28at.com

對于上面查看對象大小的代碼先在IDEA中設置一些jvm的參數。EAc28資訊網——每日最新資訊28at.com

XX:-UseCompressedOops禁止指針壓縮EAc28資訊網——每日最新資訊28at.com

運行結果EAc28資訊網——每日最新資訊28at.com

圖片圖片EAc28資訊網——每日最新資訊28at.com

可以發現對象對齊沒有了,但是多了一個對象頭,也就是說會有兩個4字節大小的位置來存儲類型指針。包括A類中name和Object對象也都是8字節,這些對象都是放在堆中的,如果不開啟指針壓縮,會無形的增大很多空間,會導致整個堆的壓力非常大,很容易就放滿,然后GC...EAc28資訊網——每日最新資訊28at.com

1.jdk1.6 update14開始,在64bit操作系統中,JVM支持指針壓縮。EAc28資訊網——每日最新資訊28at.com

2.jvm配置參數:UseCompressedOops,compressed--壓縮、oop(ordinary object pointer)--對象指針。EAc28資訊網——每日最新資訊28at.com

3.啟用指針壓縮:-XX:+UseCompressedOops(默認開啟),禁止指針壓縮:-XX:-UseCompressedOops。EAc28資訊網——每日最新資訊28at.com

為什么要進行指針壓縮?

1.在64位平臺的HotSpot中使用32位指針(實際存儲用64位),內存使用會多出1.5倍左右,使用較大指針在主內存和緩存之間移動數據,占用較大寬帶,同時GC也會承受較大壓力。EAc28資訊網——每日最新資訊28at.com

2.為了減少64位平臺下內存的消耗,啟用指針壓縮功能。EAc28資訊網——每日最新資訊28at.com

3.在jvm中,32位地址最大支持4G內存(2的32次方),但是現在的機器基本都是64位的,也就是2的64次方,這絕對是一個非常大的數字,也就是64位能表述的內存非常大,可以通過對對象指針的存入堆內存時壓縮編碼、取出到cpu寄存器后解碼方式進行優化(對象指針在堆中是32位,在寄存器中是35位,2的35次方=32G),使得jvm只用32位地址就可以支持更大的內存配置(小于等于32G)。EAc28資訊網——每日最新資訊28at.com

4.堆內存小于4G時,不需要啟用指針壓縮,jvm會直接去除高32位地址,即使用低虛擬地址空間。EAc28資訊網——每日最新資訊28at.com

5.堆內存大于32G時,壓縮指針會失效,會強制使用64位(即8字節)來對java對象尋址,這就會出現1的問題,所以堆內存不要大于32G為好。EAc28資訊網——每日最新資訊28at.com

說的簡單一點就是如果壓縮了,只占用4個字節,如果沒有壓縮占用8個字節,是為了節約內存空間。EAc28資訊網——每日最新資訊28at.com

本文鏈接:http://www.tebozhan.com/showinfo-26-35318-0.html原來New關鍵字創建對象的背后還隱藏了這么多秘密,看完這篇文章我頓悟了

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Vue3 學習筆記,快速初始化 Vue 項目及 Data 函數用法學習

下一篇: 解密 Python 如何調用 Rust 編譯生成的動態鏈接庫

標簽:
  • 熱門焦點
  • 把LangChain跑起來的三個方法

    使用LangChain開發LLM應用時,需要機器進行GLM部署,好多同學第一步就被勸退了,那么如何繞過這個步驟先學習LLM模型的應用,對Langchain進行快速上手?本片講解3個把LangChain跑起來
  • 一篇聊聊Go錯誤封裝機制

    %w 是用于錯誤包裝(Error Wrapping)的格式化動詞。它是用于 fmt.Errorf 和 fmt.Sprintf 函數中的一個特殊格式化動詞,用于將一個錯誤(或其他可打印的值)包裝在一個新的錯誤中。使
  • 如何使用JavaScript創建一只圖像放大鏡?

    譯者 | 布加迪審校 | 重樓如果您曾經瀏覽過購物網站,可能遇到過圖像放大功能。它可以讓您放大圖像的特定區域,以便瀏覽。結合這個小小的重要功能可以大大改善您網站的用戶體驗
  • 谷歌KDD'23工作:如何提升推薦系統Ranking模型訓練穩定性

    谷歌在KDD 2023發表了一篇工作,探索了推薦系統ranking模型的訓練穩定性問題,分析了造成訓練穩定性存在問題的潛在原因,以及現有的一些提升模型穩定性方法的不足,并提出了一種新
  • 小紅書1周漲粉49W+,我總結了小白可以用的N條漲粉筆記

    作者:黃河懂運營一條性教育視頻,被54萬人&ldquo;珍藏&rdquo;是什么體驗?最近,情感博主@公主是用鮮花做的,火了!僅僅憑借一條視頻,光小紅書就有超過128萬人,為她瘋狂點贊!更瘋狂的是,這
  • 共享單車的故事講到哪了?

    來源丨海克財經與共享充電寶相差不多,共享單車已很久沒有被國內熱點新聞關照到了。除了一再漲價和用戶直呼用不起了。近日多家媒體再發報道稱,成都、天津、鄭州等地多個共享單
  • 10天營收超1億美元,《星鐵》比《原神》差在哪?

    來源:伯虎財經作者:陳平安即便你沒玩過《原神》,你一定聽說過的它的大名。恨它的人把《原神》開服那天稱作是中國游戲史上最黑暗的一天,有粉絲因為索尼在PS平臺上線《原神》,怒而
  • 三星電子Q2營收60萬億韓元 存儲業務營收同比仍下滑超過50%

    7月27日消息,據外媒報道,從三星電子所發布的財報來看,他們主要利潤來源的存儲芯片業務在今年二季度仍不樂觀,營收同比仍在大幅下滑,所在的設備解決方案
  • 華為舉行春季智慧辦公新品發布會 首次推出電子墨水屏平板

    北京時間2月27日晚,華為在巴塞羅那舉行春季智慧辦公新品發布會,在海外市場推出之前已經在中國市場上市的筆記本、平板、激光打印機等辦公產品,并首次推出搭載
Top