日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

JAVA是一座圍城,Java開發(fā)不需要像C、C++開發(fā)人員那樣,維護每個對象從開始到終結(jié)的職責(zé)。因為Java虛擬機會幫助我們完成這些職責(zé),但是一旦發(fā)生內(nèi)存泄漏和溢出,就需要我們排查。

圖解Java內(nèi)存區(qū)域

 

Java虛擬機執(zhí)行Java程序時,把它管理的整個內(nèi)存區(qū)域稱為運行時數(shù)據(jù)區(qū)。同時根據(jù)區(qū)域的用途,以及創(chuàng)建和銷毀時間等因素,將運行時數(shù)據(jù)區(qū)分成不同的區(qū)域。

圖解Java內(nèi)存區(qū)域

 

程序計數(shù)器

程序計數(shù)器表示當(dāng)前線程所執(zhí)行字節(jié)碼指令的行號計數(shù)器。字節(jié)碼解釋器通過改變程序計數(shù)器的值,選取下一條需要執(zhí)行的指令。為了保證線程切換之后恢復(fù)到正確的執(zhí)行位置,每條線程都需要獨立的程序計數(shù)器,所以程序計數(shù)器是線程私有的。同時程序計數(shù)器是唯一一個在虛擬機規(guī)范中沒有規(guī)定 OutOfMemoryError 的區(qū)域。

注:線程執(zhí)行Java方法,程序計數(shù)器記錄字節(jié)碼指令地址;如果執(zhí)行的是本地(Native)方法,程序計數(shù)器為空。

圖解Java內(nèi)存區(qū)域

 

虛擬機棧

虛擬機棧是Java方法執(zhí)行的線程內(nèi)存模型。每個方法的執(zhí)行,Java虛擬機都會創(chuàng)建一個棧幀存儲方法相關(guān)變量。每個方法被調(diào)用到執(zhí)行完畢的過程,對應(yīng)棧幀在虛擬機棧中入棧到出棧的過程。

如下圖所示,當(dāng)虛擬機執(zhí)行 swap(a,b) 方法時,會創(chuàng)建一個單獨的棧幀 swap(a,b) 棧幀,在該棧幀中會存儲于方法相關(guān)的變量,該棧幀的入棧和出棧操作對應(yīng)著方法的執(zhí)行和結(jié)束。

圖解Java內(nèi)存區(qū)域

 

每個棧幀都包含了局部變量表、操作數(shù)、動態(tài)鏈接、方法返回值。

  • 局部變量表:存放方法參數(shù)和內(nèi)部定義的局部變量。局部變量表的容量以變量槽為最小單位每個變量槽可以存放一個 boolean 、 byte 、 char 、 short 、 int 、 float 、 reference 、 returnAddress 數(shù)據(jù)類型。
  • 操作數(shù)棧:底層也是棧結(jié)構(gòu),是進行數(shù)據(jù)運算的地方。當(dāng)一個方法剛剛開始執(zhí)行時,其操作數(shù)棧是空的,隨著方法執(zhí)行和字節(jié)碼指令的執(zhí)行,會從局部變量表或?qū)ο髮嵗淖侄沃袕?fù)制常量或變量寫入到操作數(shù)棧,再隨著計算的進行將棧中元素出棧到局部變量表或者返回給方法調(diào)用者,也就是出棧/入棧操作。
  • 動態(tài)鏈接:將常量池中指向方法的部分符號引用,在方法運行期間轉(zhuǎn)為直接引用。字節(jié)碼中的方法調(diào)用指令就是以常量池中指向方法的符號引用作為參數(shù)。這些符號引用一部分會在類加載階段或第一次使用時轉(zhuǎn)化為直接引用,這種轉(zhuǎn)化稱為靜態(tài)解析。另一部分將在每一次運行期間轉(zhuǎn)化為直接引用,這部分稱為動態(tài)連接。
  • 返回地址:方法執(zhí)行退出后,返回到方法被調(diào)用的地方。
圖解Java內(nèi)存區(qū)域

 

在 swap 函數(shù)執(zhí)行的過程中, a 、 b 、 temp 都會保存到局部變量表中,其中的賦值操作則通過操作數(shù)棧執(zhí)行,

方法執(zhí)行完畢返回到調(diào)用的地方的地址則存儲在返回地址中。

圖解Java內(nèi)存區(qū)域

 

本地方法棧

本地方法棧與 Java 虛擬機棧所發(fā)揮的作用是非常相似的,其區(qū)別不過是虛擬機棧為虛擬機執(zhí)行 Java 方法 (也就是字節(jié)碼)服務(wù),而本地方法棧則是為虛擬機使用到的 Native 方法 服務(wù)。

Java堆

Java堆是虛擬機管理的內(nèi)存中最大的一塊,幾乎所有對象都在Java堆分配內(nèi)存。Java堆在虛擬機啟動的時候創(chuàng)建,被所有的線程共享。Java堆也會涉及到內(nèi)存回收的內(nèi)容,本片文章先不展開了。Java堆無法擴展時,會報出 OutOfMemoryError 異常。

圖解Java內(nèi)存區(qū)域

 

方法區(qū)

方法區(qū)存儲已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯后的代碼緩存等數(shù)據(jù)。方法區(qū)是各個線程共享的內(nèi)存區(qū)域。

圖解Java內(nèi)存區(qū)域

 

屏幕面前的你,會不會遇到這樣的困惑。方法區(qū)和永久代有什么關(guān)系?和元空間呢?

  • 方法區(qū)和永久代的關(guān)系方法區(qū)是JVM規(guī)范概念,而永久代則是HotSpot虛擬機特有的概念。《Java虛擬機規(guī)范》只是規(guī)定了有方法區(qū)的概念和作用,并沒有規(guī)定如何去實現(xiàn)它。那么,在不同的 JVM 上方法區(qū)的實現(xiàn)肯定是不同的了。 同時大多數(shù)用的JVM都是Sun公司的HotSpot。在HotSpot上把GC分代收集擴展至方法區(qū),或者說使用永久代來實現(xiàn)方法區(qū)。因此永久代是HotSpot的概念,方法區(qū)是Java虛擬機規(guī)范中的定義,是一種規(guī)范,而永久代是一種實現(xiàn),一個是標(biāo)準(zhǔn)一個是實現(xiàn)。其他的虛擬機實現(xiàn)并沒有永久帶這一說法。在1.7之前在(JDK1.2 ~ JDK6)的實現(xiàn)中,HotSpot 使用永久代實現(xiàn)方法區(qū),HotSpot 使用 GC分代來實現(xiàn)方法區(qū)內(nèi)存回收,可以使用如下參數(shù)來調(diào)節(jié)方法區(qū)的大小。
  • 元空間對于Java8, HotSpots取消了永久代,取代永久代的就是元空間。永久代存在內(nèi)存上限( -XX:MaxPermSize ,即使不設(shè)置也有默認(rèn)大小),當(dāng)進程申請不到足夠的內(nèi)存,會造成內(nèi)存溢出。改成元空間后,改用本地內(nèi)存,只要本地空間足夠,就不會有內(nèi)存溢出的問題。元空間和永久代有什么不同的?存儲位置不同,永久代物理是是堆的一部分,和新生代,老年代地址是連續(xù)的,而元空間屬于本地內(nèi)存;存儲內(nèi)容不同,元空間存儲類的元信息,靜態(tài)變量和常量池等并入堆中。相當(dāng)于永久代的數(shù)據(jù)被分到了堆和元空間中。

運行時常量池

運行時常量池是方法區(qū)的一部分,是一塊內(nèi)存區(qū)域。Class 文件常量池將在類加載后進入方法區(qū)的運行時常量池中存放。 一個類加載到 JVM 中后對應(yīng)一個運行時常量池。

圖解Java內(nèi)存區(qū)域

 

易混淆的概念

屏幕面前的你,會不會遇到這樣的困惑。運行時常量池和Class文件常量池有什么關(guān)系?和字符串常量池呢?和緩沖池呢?

Class文件常量池

Class 文件常量池,用于存放編譯期生成的各種字面量和符號引用,這部分內(nèi)容將在類加載后進入方法區(qū)的運行時常量池中存放。常量池中主要存放兩大類常量:字面量和符號引用。當(dāng)Class文件常量池加載到方法區(qū)時,會把符號引用轉(zhuǎn)換為直接引用,存放到運行時常量池。

圖解Java內(nèi)存區(qū)域

 


圖解Java內(nèi)存區(qū)域

 

字符串常量池

字符串常量池是 全局的, JVM 中獨此一份 ,因此也稱為全局字符串常量池。

其中:

在 jdk1.6(含) 之前也是方法區(qū)的一部分,并且其中存放的是字符串的實例; 在 jdk1.7(含) 之后是在堆內(nèi)存之中, 存儲的是字符串對象的引用,字符串實例是在堆中;

底層原理

在 HotSpot VM 里實現(xiàn)線程池功能的是一個 StringTable 類,它是一個Hash表,默認(rèn)值大小長度是1009;這個 StringTable 在每個 HotSpot VM 的實例只有一份,被所有的類共享。字符串常量由一個一個字符組成,放在了 StringTable 上。

String str1 = "圖解Java";
String str2 = new String("圖解Java");
System.out.println(str1 == str2);

在這段代碼中,當(dāng)執(zhí)行 String str1 = "圖解Java" 時,先到常量池中查詢有沒有 "圖解Java" 字符串的引用,如果沒有,則會在 Java堆 上創(chuàng)建 "圖解Java" 字符串,在常量池中存儲字符串的地址, str1 則指向字符串常量池的地址。

String str2 = new String("圖解Java") ,則會直接在Java堆中創(chuàng)建對象。 str2 指向堆中的地址。

看到這里,屏幕面前的你有沒有想到最后的結(jié)果是 false 呢。

如果此時還有 String str3 = "圖解Java" 那么 str1==str3 的結(jié)果是什么?

此時 str3 發(fā)現(xiàn)字符串常量池中已經(jīng)有了 "圖解Java" 字符串的引用,則直接返回,不會創(chuàng)建新的對象。

看到這里,屏幕面前的你有沒有想到最后的結(jié)果是 true 呢。

圖解Java內(nèi)存區(qū)域

 

JVM 中除了字符串常量池,8種基本數(shù)據(jù)類型中除了兩種浮點類型剩余的6種基本數(shù)據(jù)類型的包裝類,都使用了緩沖池技術(shù),但是 Byte 、 Short 、 Integer 、 Long 、 Character 這5種整型的包裝類也只是在對應(yīng)值在 [-128,127] 時才會使用緩沖池,超出此范圍仍然會去創(chuàng)建新的對象。

Class文件常量池、運行時常量池、字符串常量池的聯(lián)系

我們平時寫好的Java代碼即Java格式的文件,經(jīng)過編譯,會變成Class類型的文件。而Class文件有一部分是Class文件常量池,用于存儲字面量和符號引用。

Class文件經(jīng)過類加載器加載后,之前Class文件常量池的內(nèi)容會存放到方法區(qū)的運行時常量池,需要注意的是Class文件常量池的符號引用會轉(zhuǎn)變直接引用存入運行時常量池。

字符串常量池是 JVM 的一部分,整個 JVM 只有一份,在將Class文件常量池的字面量也會在類加載的時候進入到字符串常量池中。

份數(shù)內(nèi)容Class文件常量池每個類對應(yīng)一份字面量、符號引用運行時常量池每個類對應(yīng)一份字面量、直接引用字符串常量池整個 JVM 僅有一份字符串

圖解Java內(nèi)存區(qū)域

 

分享到:
標(biāo)簽:內(nèi)存 Java
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定