中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JVM內存模型與運行時數據區域的案例分析

發布時間:2020-10-26 10:32:57 來源:億速云 閱讀:185 作者:小新 欄目:編程語言

這篇文章給大家分享的是有關JVM內存模型與運行時數據區域的案例分析的內容。小編覺得挺實用的,因此分享給大家做個參考。一起跟隨小編過來看看吧。

一、java內存模型

JVM內存模型與運行時數據區域的案例分析

java定義內存模型的目的是:為了屏蔽各種硬件和操作系統的內存訪問之間的差異。

java內存模型規定了所有的變量都存儲在主內存中,每條線程擁有自己的工作內存,工作內存保存了主內存中變量的副本。

線程對變量操作只能在工作內存中進行,不能直接讀寫主內存的變量。

不同線程之間的變量訪問需要通過主內存來完成。

1、java內存模型和java運行時數據區域的關系:主內存對應著java堆,工作內存對應著java棧。

2、volatile關鍵字,使得變量的更新在各個工作內存中都是實時可見的。在DCL的單例模式中有運用到

二、java運行時數據區域/內存區域

因為jvm的運行時數據區域一直在改善,所以不同jdk版本之間會有不同。

1、jdk1.7之前的jvm內存區域,擁有永久代

JVM內存模型與運行時數據區域的案例分析

1、程序計數器的作用,因為.java文件被編譯成.class文件,它作為當前線程所執行的字節碼的行號指示器。當字節碼解釋器工作時,就是通過改變這個計算器的值來選取下一條要執行的字節碼指令。每條線程都有一個獨立的程序計數器。

2、本地方法棧就是執行本地native方法的棧,native方法由虛擬機實現!

3、java虛擬機棧描述的是該線程執行java方法(method)時的內存模型。每一個方法都對應一個棧幀,棧幀中的局部變量表存儲了方法中的基本數據類型變量、對象引用變量。

JVM內存模型與運行時數據區域的案例分析

如上圖所示,局部變量表保存了方法中聲明的8種基本類型變量和對象引用變量。每一個棧幀中還有一個指向運行時常量池的引用,這是指String類型。下面有一個經典的String對象生成的面試題!

4、java堆是JVM中內存最大的一塊,被所有線程共享。幾乎所有的對象實例都在這里分配,所以java堆也是JVM垃圾回收的主要區域。java堆又被分成了年輕代,老年代;年輕代進一步可以劃分為Eden空間,From Survivor空間、To Survivor空間。

JVM內存模型與運行時數據區域的案例分析

當我們使用new關鍵字分配對象時,就是在java堆中生成對象。

下面分析一下對象生成時的情況。

  1. 因為Eden最大,所以新生成的對象都分配到Eden空間,當Eden空間快滿時,進行一次Minor GC,然后將存活的對象復制到From Survivor空間。這時,Eden空間繼續向外提供堆內存。

  2. 后面繼續生成的對象還是放到Eden空間,當Eden空間又要滿的時候,這時候Eden空間和From Survivor空間同時進行一次Minor GC,然后把存活對象放到To Survivor空間。這時,Eden空間繼續向外提供堆內存。

  3. 接下來的情況和2一致。Eden空間快滿的時候,Eden空間和To Survivor空間進行一次Minor GC,然后存活的對象放到From Survivor空間。

  4. 接下來的情況和3一致。Eden空間快慢的時候,Eden空間和From Survivor空間進行一次Minor GC,然后存活的對象放到To Survivor空間。

  5. 就是說2個Survivor中的一個用來提供對象保存。當Eden空間和某一塊Survivor空間GC后,另一塊Survivor空間放不下GC后存活的對象;或者是連續Minor GC15次左右的情況;就把這部分存活對象放入到老年代空間。

  6. 當老年代空間也放滿的時候,進行Major GC,對老年代空間進行回收。(也叫做Full GC,Full GC的內存消耗很大,應該避免)

年輕代使用的是復制算法:每次Minor GC把Eden區和一塊Survivor區的存活對象復制到另一塊Survivor區。老年代使用的是標記-整理算法:每次Major GC把存活對象都想內存空間的一端移動,然后直接清理掉端邊界以外的內存。

大對象如數組、很長的字符串,直接進入老年代空間。

5、方法區用于存儲JVM加載的類信息、final常量、static靜態變量等數據,方法區中的數據都是整個程序中唯一的。方法區還包含了運行時常量池,主要存放編譯期生成的字面量和符號引用(在類加載后放入)。String對象的字面量就會被放入到運行時常量池中。

垃圾回收在方法區主要是對常量的回收和對類型的卸載。

2、jdk1.8及之后的jvm內存區域,元空間取代了永久代

JVM內存模型與運行時數據區域的案例分析

元空間和永久代的性質是一樣的,都是對JVM方法區的實現,作用是一樣的。不過元空間與永久代之間最大的區別在于:元空間并不在虛擬機JVM內存中,而是使用本地內存。

為什么用元空間取代永久代呢?

  1. 字符串存在永久代中,容易出現性能問題和內存溢出。

  2. 類及方法的信息等比較難確定其大小,因此對于永久代的大小指定比較困難,太小容易出現永久代溢出,太大則容易導致老年代溢出。

  3. 永久代會為GC帶來不必要的復雜度,并且回收效率偏低。

直接內存

JDK1.4之后加入的NIO,引入了基于通道channel和緩沖區buffer的IO,直接使用native函數分配堆外內存,顯著提高IO性能,避免了原來BIO的在java堆和naive堆中來回復制數據。

JVM內存模型與運行時數據區域的案例分析

3、字符串String生成時的內存分配情況

參考文章:Java中字符串常量池的詳解。

4、生成對象時的內存情況

下面來分析一下我們常見的生成對象或基本數據類型變量的內存模型。這樣可以對JVM有一個更好的理解。

int i =3;,一個方法對應一個棧幀,方法中的基本數據類型變量直接在棧幀中分配。如果是static、final類型的基本數據類型則存儲在運行時常量池中,和String一樣。

Object o1 = new Object();,對象引用(Object o1)存儲在棧幀中,但是對象數據(new Object())存儲在java堆中,對象類型數據(Class等信息)存儲在方法區中。

String s1 = new String("abcd");,使用new聲明的對象,對象引用(String s1)存儲在棧幀中,對象數據(new String(“abcd”))存儲在java堆中,字符串值(“abcd”)存儲在運行時常量池中。

String s2 = “abc”,對象引用(String s2)存儲在棧幀中,字符串值(“abc”)存儲在運行時常量池中。

JVM內存模型與運行時數據區域的案例分析

java棧、java堆、方法區這3者之間的關系大概就是上面的分析所示。

3、各種異常分析

1、java堆內存溢出錯誤OutOfMemoryError

如果java堆中分配的對象太多,且GC后內存空間還是不夠用。下面通過循環生成對象來消耗內存空間進行測試。

相關指令:VM Args: -Xms20m -Xmx40m,表示JVM分配的堆內存最小為20MB,最大為40MB。

 public static void main(String[] args) {
   while (true) {
     List<Object> list = new ArrayList<>(10);
     list.add(new Object());
   }
 }

2、java棧堆棧溢出錯誤StackoverflowError

如果java棧的棧深度大于JVM允許的深度,就會拋出該錯誤。下面通過無限遞歸調用來進行堆棧進行測試。

相關指令:VM Args: -Xss128k,表示JVM分配的棧容量為128KB。

public class StackOOM {
    
    private int length = 1;
    
    public void stackLeak() {
        length++;
        stackLeak();
    }
    
    public static void main(String[] args) {
        StackOOM stackOOM = new StackOOM();
        stackOOM.stackLeak();
    }
}

JVM內存模型與運行時數據區域的案例分析

感謝各位的閱讀!關于JVM內存模型與運行時數據區域的案例分析就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

jvm
AI

江陵县| 陆丰市| 汝城县| 台南市| 丹阳市| 临潭县| 棋牌| 梁平县| 莱西市| 万安县| 宿州市| 延川县| 伊春市| 永仁县| 河间市| 温宿县| 扶余县| 元阳县| 伽师县| 南皮县| 洞头县| 巴彦县| 临城县| 方山县| 藁城市| 嘉兴市| 张家口市| 正蓝旗| 葵青区| 望都县| 靖边县| 甘洛县| 曲阜市| 伊通| 定陶县| 安新县| 县级市| 枞阳县| 哈密市| 突泉县| 江西省|