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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java虚拟机详解02----JVM内存结构

發布時間:2025/4/16 java 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java虚拟机详解02----JVM内存结构 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

主要內容如下:

  • JVM啟動流程
  • JVM基本結構
  • 內存模型
  • 編譯和解釋運行的概念

?

一、JVM啟動流程:

JVM啟動時,是由java命令/javaw命令來啟動的。

二、JVM基本結構:

JVM基本結構圖:

《深入理解Java虛擬機(第二版)》中的描述是下面這個樣子的:

?

Java中的內存分配:

Java程序在運行時,需要在內存中的分配空間。為了提高運算效率,就對數據進行了不同空間的劃分,因為每一片區域都有特定的處理數據方式和內存管理方式。

具體劃分為如下5個內存空間:(非常重要)

  • :存放局部變量
  • :存放所有new出來的東西
  • 方法區:被虛擬機加載的類信息、常量、靜態常量等。
  • 程序計數器(和系統相關)
  • 本地方法棧

1、程序計數器:

每個線程擁有一個PC寄存器

在線程創建時創建

指向下一條指令的地址

執行本地方法時,PC的值為undefined

2、方法區:?

保存裝載的類信息

  類型的常量池

  字段,方法信息

  方法字節碼

通常和永久區(Perm)關聯在一起

3、堆內存:

和程序開發密切相關

應用系統對象都保存在Java堆中

所有線程共享Java堆

對分代GC來說,堆也是分代的

GC管理的主要區域

現在的GC基本都采用分代收集算法,如果是分代的,那么堆也是分代的。如果堆是分代的,那堆空間應該是下面這個樣子:

上圖是堆的基本結構,在之后的文章中再進行詳解。

4、棧內存:

  • 線程私有,生命周期和線程相同
  • 棧由一系列幀組成(因此Java棧也叫做幀棧)
  • 幀保存一個方法的局部變量、操作數棧、常量池指針
  • 每一次方法調用創建一個幀,并壓棧

解釋:

Java虛擬機棧描述的是Java方法執行的內存模型每個方法被調用的時候都會創建一個棧幀,用于存儲局部變量表、操作棧、動態鏈接、方法出口等信息。每一個方法被調用直至執行完成的過程就對應著一個棧幀在虛擬機中從入棧到出棧的過程

在Java虛擬機規范中,對這個區域規定了兩種異常情況:

??? (1)如果線程請求的棧深度太深,超出了虛擬機所允許的深度,就會出現StackOverFlowError(比如無限遞歸。因為每一層棧幀都占用一定空間,而 Xss 規定了棧的最大空間,超出這個值就會報錯)

??? (2)虛擬機棧可以動態擴展,如果擴展到無法申請足夠的內存空間,會出現OOM

?

4.1? Java棧之局部變量表:包含參數和局部變量

??? 局部變量表存放了基本數據類型、對象引用和returnAddress類型(指向一條字節碼指令的地址)。其中64位長度的long和double類型的數據會占用2個局部變量空間(slot),其余數據類型只占用1個。局部變量表所需的內存空間在編譯期間完成分配。

例如,我寫出下面這段代碼:

1 package test03; 2 3 /** 4 * Created by smyhvae on 2015/8/15. 5 */ 6 public class StackDemo { 7 8 //靜態方法 9 public static int runStatic(int i, long l, float f, Object o, byte b) { 10 return 0; 11 } 12 13 //實例方法 14 public int runInstance(char c, short s, boolean b) { 15 return 0; 16 } 17 18 }

?

上方代碼中,靜態方法有6個形參,實例方法有3個形參。其對應的局部變量表如下:

上方表格中,靜態方法和實例方法對應的局部變量表基本類似。但有以下區別:實例方法的表中,第一個位置存放的是當前對象的引用

?

4、2? Java棧之函數調用組成棧幀

方法每次被調用的時候都會創建一個棧幀例如下面這個方法

public static int runStatic(int i,long l,float f,Object o ,byte b){return runStatic(i,l,f,o,b); }

?

當它每次被調用的時候,都會創建一個幀,方法調用結束后,幀出棧。如下圖所示:

?

4.3? Java棧之操作數棧

Java沒有寄存器,所有參數傳遞都是使用操作數棧

例如下面這段代碼:

public static int add(int a,int b){int c=0;c=a+b;return c;}

?

壓棧的步驟如下:

  0:?? iconst_0 // 0壓棧

  1:?? istore_2 // 彈出int,存放于局部變量2

  2:?? iload_0? // 把局部變量0壓棧

  3:?? iload_1 // 局部變量1壓棧

  4:?? iadd????? //彈出2個變量,求和,結果壓棧

  5:?? istore_2 //彈出結果,放于局部變量2

  6:?? iload_2? //局部變量2壓棧

  7:?? ireturn?? //返回

如果計算100+98的值,那么操作數棧的變化如下圖所示:

?

?

4.4? Java棧之棧上分配:

小對象(一般幾十個bytes),在沒有逃逸的情況下,可以直接分配在棧上

直接分配在棧上,可以自動回收,減輕GC壓力

大對象或者逃逸對象無法棧上分配

棧、堆、方法區交互:

?

?

三、內存模型:

每一個線程有一個工作內存。工作內存和主存獨立。工作內存存放主存中變量的值的拷貝。

當數據從主內存復制到工作存儲時,必須出現兩個動作:第一,由主內存執行的讀(read)操作;第二,由工作內存執行的相應的load操作;當數據從工作內存拷貝到主內存時,也出現兩個操作:第一個,由工作內存執行的存儲(store)操作;第二,由主內存執行的相應的寫(write)操作。

每一個操作都是原子的,即執行期間不會被中斷

對于普通變量,一個線程中更新的值,不能馬上反應在其他變量中。如果需要在其他線程中立即可見,需要使用volatile關鍵字作為標識。

1、可見性:

  一個線程修改了變量,其他線程可以立即知道

保證可見性的方法:

volatile

synchronized (unlock之前,寫變量值回主存)

final(一旦初始化完成,其他線程就可見)

2、有序性:

  在本線程內,操作都是有序的

  在線程外觀察,操作都是無序的。(指令重排 或 主內存同步延時)

3、指令重排:

指令重排:破壞了線程間的有序性:

?

?

指令重排:保證有序性的方法:

指令重排的基本原則:

程序順序原則:一個線程內保證語義的串行性

volatile規則:volatile變量的寫,先發生于讀

鎖規則:解鎖(unlock)必然發生在隨后的加鎖(lock)前

傳遞性:A先于B,B先于C 那么A必然先于C

線程的start方法先于它的每一個動作

線程的所有操作先于線程的終結(Thread.join())

線程的中斷(interrupt())先于被中斷線程的代碼

對象的構造函數執行結束先于finalize()方法

?

四、解釋運行和編譯運行的概念:

解釋運行:

解釋執行以解釋方式運行字節碼

解釋執行的意思是:讀一句執行一句

編譯運行(JIT):

將字節碼編譯成機器碼

直接執行機器碼

運行時編譯

編譯后性能有數量級的提升

編譯運行的性能優于解釋運行。

?

轉載于:https://www.cnblogs.com/qianguyihao/p/4748392.html

總結

以上是生活随笔為你收集整理的Java虚拟机详解02----JVM内存结构的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。