為了賬號安全,請及時綁定郵箱和手機立即綁定

JVM系列分析- 內存模型

2018.02.26 17:00 11840瀏覽

JVM的內存模型是java語言繞不開的一個話題。要進行java的性能調優,首先就要了解其內存模型。在諸多的面試筆試中,這也是很多面試官會考察的內容。

本篇文章簡單介紹JVM內存模型的概念,結構和對應的參數設置,并根據具體的代碼案例講解一下內存分配情況。

1.JVM內存結構

圖片描述

由圖可以較為清楚的看到,JVM的內存空間分為3大部分,分別是堆內存、方法區和棧內存。其中棧內存可以再細分為java虛擬機棧和本地方法棧。堆內存可以劃分為新生代和老年代。新生代中還可以再次劃分為Eden區、From Survivor區和To Survivor區。劃分出來的各個區,分別保存不同的數據,并且在一般情況下,其采取的內存回收策略也是不同的。

2.JVM內存區域功能

圖片描述

通過上圖可以看到JVM運行時的數據區:

2.1 堆內存

堆內存是JVM內存模型中最大的一塊區域,被所有線程共享,是在JVM啟動時候進行創建的。幾乎所有的對象的空間分配都是在堆內存上進行分配的。

考慮到JVM的內存回收機制,堆內存可以劃分為新生代和老年代兩個區域(默認新生代與老年代的空間大小為1:2)。新生代可以再劃分為Eden區、From Survivor區和To Survivor區(三者比例為8:1:1)。幾乎所有的新對象的創建都是在Eden區進行的。在垃圾回收(GC)過程中,Eden中的活躍對象會被轉移到Survivor區,當再到達一定的年齡(經歷過的Minor GC的次數),會被轉移到老年代中。

堆可以處于物理上不連續的內存空間中,但是需要滿足邏輯上的連續。在實現時,可以實現成固定大小的,也可以是可擴展的,不過當前主流的虛擬機都是按照可擴展來實現的

2.2 方法區

方法區又被成為永久代(HotSpot虛擬機的設計團隊選擇把GC分代收集擴展至方法區),同樣也是被所有的線程共享的。該區域中主要保存類的信息、靜態變量、常量和即時編譯器編譯后的代碼等數據。

JDK1.7中,已經把放在永久代的字符串常量池移到堆中。JDK1.8撤銷永久代,引入元空間。

方法區不需要連續的內存,可以選擇固定大小或者可擴展。并且還可以選擇不實現垃圾收集。相對而言,垃圾收集行為在這個區域是比較少出現的,但并非數據進入了方法區就如永久代的名字一樣“永久”存在了。這個區域的內存回收目標主要是針對常量池的回收和對類型的卸載,一般來說這個區域的回收“成績”比較難以令人滿意,尤其是類型的卸載,條件相當苛刻,但是這部分區域的回收確實是有必要的。當方法區無法滿足內存分配需求時,將拋出OutOfMemoryError異常。

2.3 程序計數器

程序計數器是用于標識當前線程執行的字節碼文件的行號指示器。多線程情況下,每個線程都具有各自獨立的程序計數器,所以該區域是非線程共享的內存區域。

當執行java方法時候,計數器中保存的是字節碼文件的行號;當執行Native方法時,計數器的值為空。

2.4 Java棧

java棧是線程私有的內存區域,其中存儲的是棧幀。對于一個java的方法,其開始調用,則會創建一個棧幀,保存到java棧中;當該方法執行完成,則對應的是出棧的過程。

如果方法methodOne方法調用了methodTwo,那么methodOne就會先入棧創建一個棧楨,接著methodTwo再入棧成為棧頂(假設沒有其他的方法執行),methodTwo執行完先出棧,接著methodOne執行完出棧。

每個棧幀中,保存執行對應方法所必須的信息,主要包含局部變量表,操作棧,動態連接和方法出口等信息。

局部變量表中,可以存放的數據有8種基本數據類型(boolean,byte,char,short,int,float,long,double),對象引用和returnAddress類型。其中long和double因為是64位,會占用兩個局部變量的空間。

在Java虛擬機規范中,對這個區域規定了兩種異常狀況:如果線程請求的棧深度大于虛擬機所允許的深度(比如遞歸調用的時候),將拋出StackOverflowError異常;如果虛擬機棧可以動態擴展(當前大部分的Java虛擬機都可動態擴展,只不過Java虛擬機規范中也允許固定長度的虛擬機棧),當擴展時無法申請到足夠的內存時會拋出OutOfMemoryError異常。

2.5 本地方法棧

本地方法棧也是線程私有的內存區域,與java棧比較相似,不同之處在于該區域主要是保存Native方法相關的數據。Native方法是非Java語言編寫的方法。

與虛擬機棧一樣,本地方法棧區域也會拋出StackOverflowError和OutOfMemoryError異常。

3.JVM內存參數設置

圖片描述

  • -Xms設置堆的最小空間大小。
  • -Xmx設置堆的最大空間大小。
  • -XX:NewSize設置新生代最小空間大小。
  • -XX:MaxNewSize設置新生代最大空間大小。
  • -XX:PermSize設置永久代最小空間大小。
  • -XX:MaxPermSize設置永久代最大空間大小。
  • -Xss設置每個線程的堆棧大小。

    4.代碼案例講解

    使用如下的一段簡單代碼案例,說明一下各個內存區域中保存的信息。
    圖片描述

  • 堆中進行對象的空間分配,比如Hashtable對象和String對象。

  • 方法中保存類信息(TestJVM),方法(put方法,print方法,test方法)和靜態變量(NUM)

  • java棧中保存對象引用(score)
    5.參考資料

    http://www.ityouknow.com/jvm/2017/08/25/jvm-memory-structure.html

http://blog.csdn.net/liyantianmin/article/details/50704434

點擊查看更多內容

本文原創發布于慕課網 ,轉載請注明出處,謝謝合作

26人點贊

若覺得本文不錯,就分享一下吧!

評論

相關文章推薦

正在加載中
意見反饋 幫助中心 APP下載
官方微信

舉報

0/150
提交
取消
lpl竞猜