JVM內存劃分

不同版本JVM內存劃分的變化

1.6教寂,使用永久代(PermGen)來實現方法區(qū)捏鱼,運行時常量池在方法區(qū)中。

1.7酪耕,還有永久代导梆,運行時常量池在堆中。

1.8,沒有永久代看尼,使用元空間(在直接內存)

總結:1.7 運行時常量池到了堆递鹉,1.8方法區(qū)被元空間替換

什么變量會在棧里,什么變量會在堆里藏斩?

方法里的局部變量

對象中的成員變量


JVM 內存結構

JVM內存的劃分

(1)線程私有區(qū):

  • 程序計數器躏结,記錄正在執(zhí)行的虛擬機字節(jié)碼的地址;
  • Java虛擬機棧:Java方法執(zhí)行的內存區(qū)狰域,每個方法執(zhí)行時會在虛擬機棧中創(chuàng)建棧幀媳拴;
  • 本地方法棧:虛擬機的Native方法執(zhí)行的內存區(qū);

(2)線程共享區(qū):

  • Java堆:對象分配內存的區(qū)域北专;

  • 方法區(qū):存放類信息禀挫、常量、靜態(tài)變量拓颓、編譯器編譯后的代碼等數據语婴;

    • 常量池:存放編譯器生成的各種字面量和符號引用,是方法區(qū)的一部分驶睦。

程序計數器(PC 寄存器)

程序計數器的定義

程序計數器是一塊較小的內存空間砰左,是當前線程正在執(zhí)行的那條字節(jié)碼指令的地址。若當前線程正在執(zhí)行的是一個本地方法场航,那么此時程序計數器為Undefined缠导。

程序計數器的作用

  • 字節(jié)碼解釋器通過改變程序計數器來依次讀取指令,從而實現代碼的流程控制溉痢。
  • 在多線程情況下僻造,程序計數器記錄的是當前線程執(zhí)行的位置,從而當線程切換回來時孩饼,就知道上次線程執(zhí)行到哪了髓削。

Java 虛擬機棧(Java 棧)

Java 虛擬機棧的定義

Java 虛擬機棧是描述 Java 方法運行過程的內存模型。

Java 虛擬機棧會為每一個即將運行的 Java 方法創(chuàng)建一塊叫做“棧幀”的區(qū)域镀娶,用于存放該方法運行過程中的一些信息立膛,如:

  • 局部變量表
  • 操作數棧
  • 動態(tài)鏈接
  • 方法出口信息

壓棧出棧過程

當方法運行過程中需要創(chuàng)建局部變量時,就將局部變量的值存入棧幀中的局部變量表中梯码。

Java 虛擬機棧的棧頂的棧幀是當前正在執(zhí)行的活動棧宝泵,也就是當前正在執(zhí)行的方法,PC 寄存器也會指向這個地址轩娶。只有這個活動的棧幀的本地變量可以被操作數棧使用儿奶,當在這個棧幀中調用另一個方法,與之對應的棧幀又會被創(chuàng)建鳄抒,新創(chuàng)建的棧幀壓入棧頂廓握,變?yōu)楫斍暗幕顒訔?/p>

方法結束后搅窿,當前棧幀被移出,棧幀的返回值變成新的活動棧幀中操作數棧的一個操作數隙券。如果沒有返回值,那么新的活動棧幀中操作數棧的操作數沒有變化闹司。


堆的定義

堆是用來存放對象的內存空間娱仔,幾乎所有的對象都存儲在堆中。

堆的特點

  • 線程共享游桩,整個 Java 虛擬機只有一個堆牲迫,所有的線程都訪問同一個堆。
  • 在虛擬機啟動時創(chuàng)建借卧。
  • 是垃圾回收的主要場所盹憎。
  • 進一步可分為:新生代(Eden區(qū) From Survior To Survivor)、老年代铐刘。

不同的區(qū)域存放不同生命周期的對象陪每,這樣可以根據不同的區(qū)域使用不同的垃圾回收算法,更具有針對性镰吵。

堆的大小既可以固定也可以擴展檩禾,但對于主流的虛擬機,堆的大小是可擴展的疤祭,因此當線程請求分配內存盼产,但堆已滿,且內存已無法再擴展時勺馆,就拋出 OutOfMemoryError 異常戏售。

Java 堆所使用的內存不需要保證是連續(xù)的。而由于堆是被所有線程共享的草穆,所以對它的訪問需要注意同步問題灌灾,方法和對應的屬性都需要保證一致性。


方法區(qū)?受到版本變化

JDK 1.8 的時候续挟,方法區(qū)被徹底移除了紧卒,取而代之是元空間,元空間使用的是直接內存诗祸。

JDK 1.8 之前永久代還沒被徹底移除的時候通常通過下面這些參數來調節(jié)方法區(qū)大小

-XX:PermSize=N //方法區(qū) (永久代) 初始大小
-XX:MaxPermSize=N //方法區(qū) (永久代) 最大大小,超過這個值將會拋出 OutOfMemoryError 異常:java.lang.OutOfMemoryError: PermGen

JDK 1.8

-XX:MetaspaceSize=N //設置 Metaspace 的初始(和最小大信芊肌)
-XX:MaxMetaspaceSize=N //設置 Metaspace 的最大大小

方法區(qū)的定義

Java 虛擬機規(guī)范中定義方法區(qū)是堆的一個邏輯部分。方法區(qū)存放以下信息:

  • 已經被虛擬機加載的類信息
  • 即時編譯器編譯后的代碼

方法區(qū)的特點

  • 線程共享直颅。 方法區(qū)是堆的一個邏輯部分博个,因此和堆一樣,都是線程共享的功偿。整個虛擬機中只有一個方法區(qū)盆佣。
  • 永久代往堡。 方法區(qū)中的信息一般需要長期存在,方法區(qū)又是堆的邏輯分區(qū)共耍,因此用堆的劃分方法虑灰,把方法區(qū)稱為“永久代”。永久代是 HotSpot 虛擬機對虛擬機規(guī)范中方法區(qū)的一種實現方式痹兜。
  • 內存回收效率低穆咐。 方法區(qū)中的信息一般需要長期存在,回收一遍之后可能只有少量信息無效字旭。主要回收目標是:對常量池的回收对湃;對類型的卸載。
  • Java 虛擬機規(guī)范對方法區(qū)的要求比較寬松遗淳。 和堆一樣拍柒,允許固定大小,也允許動態(tài)擴展屈暗,還允許不實現垃圾回收拆讯。

運行時常量池 Runtime Constant Pool

JDK1.7 及之后版本的 JVM 已經將運行時常量池從方法區(qū)中移了出來,在 Java 堆(Heap)中開辟了一塊區(qū)域存放運行時常量池恐锦。

運行時常量池是方法區(qū)的一部分往果。class文件常量池將在類加載后進入方法區(qū)的運行時常量池中存放。

一個類加載到JVM中后對應一個運行時常量池一铅,運行時常量池相對于class文件常量池來說具備動態(tài)性陕贮,即字面量可以動態(tài)的添加。Java語言并不要求常量一定只能在編譯期產生潘飘,運行期間也可能產生新的常量(基本類型包裝類和String)肮之,這些常量被放在運行時常量池中。

  • 字面量:字符串字面量和聲明為final的常量值(基本數據類型)

  • 符號引用:編譯語言層面的概念卜录,包括以下3類:

    • 類和接口的全限定名
    • 字段的名稱和描述符
    • 方法的名稱和描述符

class文件常量池(靜態(tài)常量池)

class文件常量池是指編譯生成的class字節(jié)碼文件結構中的一個常量池(Constant Pool Table)戈擒,用于存放編譯期間生成的各種字面量和符號引用,這部分內容將在類加載后艰毒,存放于方法區(qū)的運行時常量池筐高。

字符串字面量除了類中所有雙引號括起來的字符串(包括方法體內的),還包括所有用到的類名丑瞧、方法名和這些類與方法的字符串描述柑土、字段(成員變量)的名稱和描述符

聲明為final的常量值指的是成員變量,不包含本地變量绊汹,本地變量是屬于方法的稽屏。

符號引用包括類和接口的全限定名(包括包路徑的完整名)、字段的名稱和描述符西乖、方法的名稱和描述狐榔。只不過是以一組符號來描述所引用的目標坛增,和內存并無關,所以稱為符號引用薄腻,直接指向內存中某一地址的引用稱為直接引用

當類被 Java 虛擬機加載后收捣, .class 文件中的常量池就存放在方法區(qū)的運行時常量池中。

而且在運行期間庵楷,可以向常量池中添加新的常量坏晦。如 String 類的 intern() 方法就能在運行期間向常量池中添加字符串常量。

運行時常量池和字符串常量池

運行時常量池存儲的是一系列字節(jié)嫁乘,字符串是被序列化的,而不是字符串對象球碉,還有其他常量蜓斧,不止字符串。

字符串常量池是在運行時用的睁冬,里面都是java對象挎春。

字符串字面量是讀String類對象的引用。


Class類的對象存在JVM哪里直奋?

Class對象是存放在堆區(qū)的。

類的元數據(元數據并不是類的Class對象施禾,Class對象是加載的最終產品脚线。類的方法代碼,變量名弥搞,方法名邮绿,訪問權限,返回值等等都是在方法區(qū)的)才是存在方法區(qū)的攀例。


一個對象的內存劃分船逮。

https://cloud.tencent.com/developer/article/1129494

public class Student {

    private String name;
    private static Birthday birthday = new Birthday();

    public Student(String name) {
        this.name = name;
    }

    public static void main(String[] args) {
        Student s = new Student("zhangsan");
        int age = 10;
        System.out.println(age);
    }
}

class Birthday {
    private int year = 2010;
    private int month = 10;
    private int day = 1;
}
img

從內存區(qū)域來分析

  • 虛擬機棧:只存放局部變量
  • 堆:存儲對象的實例
  • 方法區(qū):存放Class信息和常量信息(final的東西)。

從變量的角度來分析

  • 局部變量:

    存放在虛擬機棧中(具體應為[棧->棧幀->局部變量表])

    • 基本類型的值直接存在棧中粤铭。如age=10
    • 如果是對象的實例挖胃,則只存儲對象實例的引用。如s=ref
  • 實例變量:存放在堆中的對象實例中梆惯。如Student的實例變量 name=ref

  • 靜態(tài)變量:

    存放在方法區(qū)中的常量池中酱鸭。如Student.class中的birthday=ref。

    • 如果常量的類型是對象的實例則只存儲對象實例的引用地址

通過變量的角度來分析加袋,我們就可以了解為什么靜態(tài)變量不用new就能調用凛辣,而實例變量必須new出對象,才能調用职烧。

參考

https://github.com/doocs/jvm/blob/master/docs/01-jvm-memory-structure.md

https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/jvm/Java%E5%86%85%E5%AD%98%E5%8C%BA%E5%9F%9F.md

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末扁誓,一起剝皮案震驚了整個濱河市防泵,隨后出現的幾起案子,更是在濱河造成了極大的恐慌蝗敢,老刑警劉巖捷泞,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異寿谴,居然都是意外死亡锁右,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門讶泰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咏瑟,“玉大人,你說我怎么就攤上這事痪署÷肱ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵狼犯,是天一觀的道長余寥。 經常有香客問我,道長悯森,這世上最難降的妖魔是什么宋舷? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮瓢姻,結果婚禮上祝蝠,老公的妹妹穿的比我還像新娘。我一直安慰自己汹来,他們只是感情好续膳,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著收班,像睡著了一般坟岔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上摔桦,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天社付,我揣著相機與錄音,去河邊找鬼邻耕。 笑死鸥咖,一個胖子當著我的面吹牛,可吹牛的內容都是我干的兄世。 我是一名探鬼主播啼辣,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼御滩!你這毒婦竟也來了鸥拧?” 一聲冷哼從身側響起党远,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎富弦,沒想到半個月后沟娱,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡腕柜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年济似,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盏缤。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡砰蠢,死狀恐怖,靈堂內的尸體忽然破棺而出唉铜,到底是詐尸還是另有隱情娩脾,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布打毛,位于F島的核電站,受9級特大地震影響俩功,放射性物質發(fā)生泄漏幻枉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一诡蜓、第九天 我趴在偏房一處隱蔽的房頂上張望熬甫。 院中可真熱鬧,春花似錦蔓罚、人聲如沸椿肩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽郑象。三九已至,卻和暖如春茬末,著一層夾襖步出監(jiān)牢的瞬間厂榛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工丽惭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留击奶,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓责掏,卻偏偏與公主長得像柜砾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子换衬,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內容

  • 一痰驱、內存模型 Java內存模型证芭,往往是指Java程序在運行時內存的模型,而Java代碼是運行在Java虛擬機之上的...
    keep_trying2017閱讀 574評論 0 0
  • jvm內存共分為虛擬機棧萄唇,堆 檩帐,方法區(qū),程序計數器另萤,本地方法區(qū)五個部分湃密。 程序計數器(線程私有): 是當前線程所執(zhí)...
    碼出高效閱讀 225評論 1 0
  • 運行時數據區(qū): 1.程序計數器( Program Counter Register) 當前線程所執(zhí)行的字節(jié)碼的行號...
    阿拉要洗澡閱讀 147評論 0 0
  • 今天是我的生日泛源,您的笑容是最美的祝福 今天,剛一打開手機忿危,微信就傳來朋友連發(fā)的幾條信息达箍,大意是“快過生日了吧,聚會...
    渤海經濟圈閱讀 300評論 0 0
  • 文|藍澈貝兒 目錄‖ 上一章 下一章 第二十七章 錯位吻 等小溪三人將東西徹底收拾好铺厨,并搬到學校宿舍的時候...
    藍澈貝兒閱讀 1,531評論 52 37