真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

JVM內(nèi)存結(jié)構(gòu)劃分的示例分析-創(chuàng)新互聯(lián)

這篇文章主要介紹JVM內(nèi)存結(jié)構(gòu)劃分的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

創(chuàng)新互聯(lián)公司2013年成立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元博望做網(wǎng)站,已為上家服務(wù),為博望各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:028-86922220

數(shù)據(jù)區(qū)域劃分

運(yùn)行時(shí)內(nèi)存區(qū)域劃分:程序計(jì)數(shù)器、虛擬機(jī)棧、本地方法棧、堆、方法區(qū)

程序計(jì)數(shù)器

  • 線程私有

  • 通過寄存器實(shí)現(xiàn)

  • 不會(huì)存在運(yùn)行溢出

當(dāng)前線程所執(zhí)行的行號(hào)指示器,記住下一條JVM指令的執(zhí)行地址

虛擬機(jī)棧

  • 垃圾回收不涉及棧內(nèi)存

  • 棧內(nèi)存是線程私有的,可以理解為線程運(yùn)行需要的內(nèi)存空間

  • 棧由棧幀組成,每個(gè)棧幀代表一個(gè)方法執(zhí)行時(shí)需要的內(nèi)存(參數(shù),局部變量,返回地址)

  • 每個(gè)線程只能有一個(gè)活動(dòng)棧幀,對(duì)應(yīng)著當(dāng)前正在執(zhí)行的那個(gè)方法

棧內(nèi)存分配過大只能支撐一定的遞歸調(diào)用,并不會(huì)影響運(yùn)行速度,還可能減少線程數(shù)量(因?yàn)槲锢韮?nèi)存是一定的)

本地方法棧

為運(yùn)行本地方法時(shí)分配的內(nèi)存(HotSpot把虛擬機(jī)棧和本地方法棧合二為一了)


  •  

  • 有垃圾回收機(jī)制

  • 線程共享,需要考慮線程安全問題

  • 存儲(chǔ)的都是對(duì)象的實(shí)例(通過new關(guān)鍵字創(chuàng)建的對(duì)象)

  • 從內(nèi)存分配的角度來說:堆中可以劃分出多個(gè)線程私有的分配緩沖區(qū)(TLAB),以提升對(duì)象分配時(shí)的效率

  • Java堆可以處于物理上不連續(xù)的內(nèi)存空間,但在邏輯上應(yīng)該視為連續(xù)的(但是對(duì)于比如數(shù)組這種大對(duì)象,可能會(huì)要求連續(xù)的內(nèi)存空間)

方法區(qū)

  • 線程共享區(qū)

  • 存儲(chǔ)已被虛擬機(jī)加載的類型信息,常量,靜態(tài)變量,即時(shí)編譯器編譯后的代碼緩存

  • 在虛擬機(jī)啟動(dòng)時(shí)被創(chuàng)建,邏輯上屬于堆的一部分(不同JVM實(shí)現(xiàn)的方式不同)

    • JDK1.6使用永久代(PerGen)作為方法區(qū)的實(shí)現(xiàn)

    • JDK1.8使用元空間(Metaspace)對(duì)方法區(qū)進(jìn)行實(shí)現(xiàn)(包含Class ClassLoader 常量池三個(gè)部分,放在直接內(nèi)存中)StringTable放在堆中(有助于垃圾回收管理)

使用場景:如Spring Mybatis使用的動(dòng)態(tài)加載

運(yùn)行時(shí)常量池

運(yùn)行時(shí)常量池是方法區(qū)的一部分

二進(jìn)制字節(jié)碼內(nèi)容:類基本信息\常量池表\類方法定義,包含了虛擬機(jī)指令

其中,常量池表中存放編譯期間生成的各種字面量(比如各種基本數(shù)據(jù)類型)與符號(hào)引用(比如,類名\方法名\參數(shù)類型),這部分內(nèi)容將在類加載后存放到方法區(qū)的運(yùn)行時(shí)常量池中,并把符號(hào)地址變?yōu)檎鎸?shí)地址

StringTable

類似于hashTable結(jié)構(gòu),不能自動(dòng)擴(kuò)容

常量池中的字符串只是符號(hào),第一次使用時(shí)才變?yōu)閷?duì)象

利用串池機(jī)制,避免重復(fù)創(chuàng)建字符對(duì)象

案例

  • 字符串拼接的原理是編譯期優(yōu)化

  • 字符串拼接原理是StringBuilder(JDK1.8)

  • 使用intern()方法,主動(dòng)將串池中還沒有的字符串對(duì)象放入串池

// StringTable [ "a", "b" ,"ab" ] hashtable 結(jié)構(gòu),不能擴(kuò)容
public class Demo1_22 {
  // 常量池中的信息,都會(huì)被加載到運(yùn)行時(shí)常量池中, 這時(shí) a b ab 都是常量池中的符號(hào),還沒有變?yōu)?nbsp;java 字符串對(duì)象
  // ldc #2 會(huì)把 a 符號(hào)變?yōu)?nbsp;"a" 字符串對(duì)象
  // ldc #3 會(huì)把 b 符號(hào)變?yōu)?nbsp;"b" 字符串對(duì)象
  // ldc #4 會(huì)把 ab 符號(hào)變?yōu)?nbsp;"ab" 字符串對(duì)象

  public static void main(String[] args) {
    String s1 = "a"; // 懶惰的
    String s2 = "b";
    String s3 = "ab";
    String s4 = s1 + s2; // new StringBuilder().append("a").append("b").toString() new String("ab")
    String s5 = "a" + "b"; // javac 在編譯期間的優(yōu)化,結(jié)果已經(jīng)在編譯期確定為ab

    System.out.println(s3 == s5);
  }
}

JDK1.7以后,利用intern()方法,會(huì)將字符串對(duì)象嘗試放入串池,如果有則并不會(huì)放入,如果沒有則放入串池, 會(huì)把串池中的對(duì)象返回;而JDK1.6調(diào)用intern()方法,是將對(duì)象拷貝一份到串池中,指向堆中的對(duì)象本身引用并不不改變

public class Demo1_23 {

  // ["ab", "a", "b"]
  public static void main(String[] args) {
    demo1();
    demo2();
  }

  static void demo1() {
    // 串池中事前沒有"ab",intern()之后,s返回的是串池中的對(duì)象
    String s = new String("a") + new String("b");

    String s1 = s.intern();

    System.out.println(s == "ab"); // true
    System.out.println(s1 == "ab");   //true
  }

  static void demo2() {
    // 串池中事前已有"ab",s返回的仍是堆中的對(duì)象
    String x = "ab";
    String s = new String("a") + new String("b");

    // 堆 new String("a")  new String("b") new String("ab")
    String s2 = s.intern(); // 將這個(gè)字符串對(duì)象嘗試放入串池,如果有則并不會(huì)放入,如果沒有則放入串池, 會(huì)把串池中的對(duì)象返回

    System.out.println( s2 == x);  // true
    System.out.println( s == x );  //false
  }
}

位置

JDK1.6時(shí),StringTable放在元空間內(nèi),屬于永久代的位置,但是StringTable占用內(nèi)存容易觸發(fā)full gc耗時(shí)較久;JDK1.7以后將StringTable放在堆內(nèi)存中,隨著內(nèi)存占用增大首先觸發(fā)minor gc,耗時(shí)較短.

直接內(nèi)存

使用Native函數(shù)直接分配堆外內(nèi)存,然后通過Java堆里的DirectByteBuffer對(duì)象作為引用對(duì)這塊內(nèi)存的引用進(jìn)行操作.
原理說明:

使用Unsafe對(duì)象完成直接內(nèi)存的分配和回收,回收時(shí)需要主動(dòng)調(diào)用freeMemory方法

ByteBuffer的實(shí)現(xiàn)類內(nèi)部使用了Cleaner(虛引用)來監(jiān)測(cè)ByteBuffer(BB)對(duì)象,一旦BB對(duì)象被垃圾回收,會(huì)有ReferenceHandler線程通過Cleaner方法調(diào)用freeMemory來釋放內(nèi)存

創(chuàng)建新對(duì)象說明

HotSpot虛擬機(jī)在Java堆中對(duì)象分配、布局和訪問的過程

對(duì)象的創(chuàng)建

new字節(jié)碼指令

虛擬機(jī)遇到new字節(jié)碼指令時(shí),首先檢查能否在常量池中定位到一個(gè)類的符號(hào)引用,并檢查該符號(hào)引用的來是否已被加載、解析和初始化。如果沒有,則執(zhí)行相應(yīng)的類加載過程。
類加載檢查后,虛擬機(jī)為新生對(duì)象分配內(nèi)存

內(nèi)存分配

對(duì)象所需的內(nèi)存大小在類加載過程中可以確定,在Java虛擬機(jī)中為對(duì)象劃分內(nèi)存時(shí)有兩種方式:指針碰撞、空閑列表
指針碰撞: 利用一個(gè)指針作為已用內(nèi)存和未用內(nèi)存的分界點(diǎn)的指示器,內(nèi)存分配就僅僅是指針的移動(dòng)。優(yōu)點(diǎn)在于不會(huì)造成內(nèi)存碎片化,但是速度較慢

空閑列表:虛擬機(jī)維護(hù)一個(gè)內(nèi)存使用記錄表,使用時(shí),從空閑的內(nèi)存區(qū)域直接劃分一塊足夠大的空間給對(duì)象實(shí)例。

內(nèi)存分配的線程安全問題

劃分可用空間后仍要考慮并發(fā)情況下對(duì)內(nèi)存的使用,有兩種方式解決內(nèi)存沖突的問題:CAS配上失敗重試、TLAB本地線程分配緩沖
TLAB:把內(nèi)存分配的動(dòng)作按照線程劃分在不同的空間之中進(jìn)行,即每個(gè)線程在Java堆中預(yù)先分配了一小塊內(nèi)存空間

對(duì)象的內(nèi)存布局

對(duì)象在堆內(nèi)存中的布局可以劃分為三個(gè)部分:對(duì)象頭、實(shí)例數(shù)據(jù)、對(duì)齊填充

對(duì)象頭

對(duì)象頭中包含兩類信息:Mark Word、類型指針

Mark Word

存儲(chǔ)對(duì)象自身運(yùn)行時(shí)數(shù)據(jù),考慮到虛擬機(jī)的空間效率,被設(shè)計(jì)成一個(gè)動(dòng)態(tài)定義的數(shù)據(jù)結(jié)構(gòu),即根據(jù)對(duì)象的狀態(tài)復(fù)用自己的存儲(chǔ)空間(數(shù)據(jù)長度在32位和64位虛擬機(jī)上分別為32個(gè)比特和64個(gè)比特)

類型指針

對(duì)象中指向它類型元數(shù)據(jù)的指針,Java虛擬機(jī)通過這個(gè)指針來確定該對(duì)象是哪個(gè)類的實(shí)例(不是所有虛擬機(jī)都必須在對(duì)象數(shù)據(jù)上保留類型指針)此外,如果對(duì)象是一個(gè)數(shù)組,對(duì)象頭中還必須擁有一塊記錄數(shù)據(jù)長度的數(shù)據(jù)

實(shí)例數(shù)據(jù)

即程序代碼里定義的各種類型的字段內(nèi)容,包括從父類繼承的或子類中定義的字段。各類數(shù)據(jù)存儲(chǔ)是按照一定順序的(long/double、ints...),而寬度相同的字段總是被分配到一起存放,所以父類中定義的變量可能會(huì)出現(xiàn)在子類之前。

對(duì)齊填充

占位符,無特殊意義

HotSpot虛擬機(jī)的自動(dòng)內(nèi)存管理系統(tǒng)要求對(duì)象的起始地址必須是8字節(jié)的整倍數(shù),若有些對(duì)象的對(duì)象頭和示例數(shù)據(jù)內(nèi)存設(shè)計(jì)不是8的倍數(shù),則需要利用占位符來進(jìn)行填充。

對(duì)象的訪問定位

Java程序通過reference數(shù)據(jù)操作對(duì)上的具體對(duì)象,主流的訪問方式有兩種:句柄、直接指針

句柄

Java堆中可能劃分出一塊內(nèi)存作為句柄池。reference中存儲(chǔ)對(duì)象的句柄地址,句柄中包含對(duì)象的實(shí)例數(shù)據(jù)和類型數(shù)據(jù)的具體地址信息。

直接指針

Java堆中對(duì)象的布局需要考慮如何放置類型數(shù)據(jù)的相關(guān)信息(如訪問信息)。reference中存儲(chǔ)的直接就是對(duì)象地址,如果只訪問對(duì)象本身,就不要多一次間接訪問的開銷

優(yōu)缺點(diǎn)

使用句柄訪問, reference數(shù)據(jù)只需關(guān)乎句柄地址,當(dāng)對(duì)象被回收或移動(dòng)后只需改變句柄中的實(shí)例數(shù)據(jù)指針,而reference本身不用修改
使用直接指針省去了一次指針定位的時(shí)間開銷,速度更快,由于Java中對(duì)象的訪問相當(dāng)頻繁,所以效果可觀。
HotSpot使用直接指針的方式

以上是“JVM內(nèi)存結(jié)構(gòu)劃分的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司行業(yè)資訊頻道!

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)建站www.cdcxhl.com,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。


本文標(biāo)題:JVM內(nèi)存結(jié)構(gòu)劃分的示例分析-創(chuàng)新互聯(lián)
路徑分享:http://weahome.cn/article/cdseog.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部