一文搞懂JVM內(nèi)存結(jié)構(gòu)荤牍,程序員必須掌握的知識

jvm內(nèi)存結(jié)構(gòu)組成

Java內(nèi)存模型(Java Memory Model ,JMM)就是一種符合內(nèi)存模型規(guī)范的框杜,屏蔽了各種硬件和操作系統(tǒng)的訪問差異的,保證了Java程序在各種平臺下對內(nèi)存的訪問都能保證效果一致的機制及規(guī)范塑陵。

簡要言之,jmm是jvm的一種規(guī)范,定義了jvm的內(nèi)存模型师幕。它屏蔽了各種硬件和操作系統(tǒng)的訪問差異,不像c那樣直接訪問硬件內(nèi)存诬滩,相對安全很多霹粥,它的主要目的是解決由于多線程通過共享內(nèi)存進行通信時,存在的本地內(nèi)存數(shù)據(jù)不一致疼鸟、編譯器會對代碼指令重排序后控、處理器會對代碼亂序執(zhí)行等帶來的問題】站担可以保證并發(fā)編程場景中的原子性浩淘、可見性和有序性。

從下圖可以看出吴攒,java內(nèi)存模型分為五大數(shù)據(jù)區(qū)域馋袜,這些區(qū)域都有各自的用途以及他們的創(chuàng)建時間和銷毀時間

其中方法區(qū)和堆是所有線程共享的,棧舶斧,本地方法棧和程序虛擬機則為線程私有的欣鳖。

程序計數(shù)器(PC寄存器)
程序計數(shù)器是一塊很小的區(qū)域,它是線程獨占區(qū)域,可以認為它是線程行號的指示器茴厉。
椩筇ǎ空間
同程序計數(shù)器一樣是線程獨占區(qū)域
每個方法被執(zhí)行的時候都會創(chuàng)建一個棧幀用于存儲局部變量表、操作數(shù)棧矾缓、動態(tài)連接怀酷、方法返回地址等信息,每一個方法被調(diào)用的過程就是對應(yīng)一個棧幀從虛擬機入棧到出棧過程(棧是先進后出)

看如下圖,可以知道代碼執(zhí)行是先從main方法執(zhí)行,入棧開始,然后調(diào)用add方法,add方法在進入入棧,執(zhí)行完畢之后add出棧,最后才main方法出棧,所以著對應(yīng)著一個棧是先進后出的結(jié)果(一個方法對應(yīng)一個棧幀)

且對于棧幀的詳細解釋參考 Java虛擬機運行時棧幀結(jié)構(gòu)

棧幀:是存儲數(shù)據(jù)結(jié)構(gòu),以及部分過程結(jié)果
棧幀的位置: 內(nèi)存 -> 運行時數(shù)據(jù)區(qū) -> 某個線程對應(yīng)的虛擬機棧 -> here[在這里]
棧幀大小確認時間: 是在編譯的時候就確認好了,不會在運行的時候受到數(shù)據(jù)變化的影響

需要注意的是,局部變量表所需要的空間大小是在編譯的過程中就已經(jīng)分配好了,當(dāng)進入一個方法的時候,在棧中所需要的局部變量表的空間是完成確認的,在方法運行期間是不會受到數(shù)據(jù)的影響

Java虛擬機棧可能出現(xiàn)兩種類型的異常:
1.線程請求的棧深度大于虛擬機允許的棧深度嗜闻,將拋出StackOverflowError蜕依。
2.虛擬機棧空間可以動態(tài)擴展琉雳,當(dāng)動態(tài)擴展是無法申請到足夠的空間時样眠,拋出OutOfMemory異常。
本地方法棧
本地方法棧與虛擬機棧的作用其實相差不大,最大一個區(qū)別就是虛擬機棧執(zhí)行的是java方法(也就是字節(jié)碼)翠肘,而本地方法棧則為虛擬機使用的native方法,native方法主要是調(diào)用的是c或者c++

可以用過unsafe類查看這些方法

堆空間
對于大多數(shù)應(yīng)用來說,堆是java虛擬機中最大的一塊區(qū)域,因為他存儲的的對象線程是共享的,所以在多線程情況下也需要進行同步機制檐束。
且主要存儲就是對象本身以及數(shù)組
方法區(qū)
方法區(qū)跟堆一樣,是所有線程共享的區(qū)域,在jdk8中叫元數(shù)據(jù)區(qū)域
用于存儲每個類的信息(類的名稱,方法信息,字段信息)、靜態(tài)變量束倍、常量被丧、以及編譯器編譯之后的代碼等
(注:在方法區(qū)中有一個非常重要的部分就是運行時常量池盟戏,它是每一個類或接口的常量池的運行時表示形式,在類和接口被加載到JVM后甥桂,對應(yīng)的運行時常量池就被創(chuàng)建出來柿究。當(dāng)然并非Class文件常量池中的內(nèi)容才能進入運行時常量池,在運行期間也可將新的常量放入運行時常量池中黄选,比如String的intern方法笛求。)

注意:在老版jdk,方法區(qū)也被稱為永久代【因為沒有強制要求方法區(qū)必須實現(xiàn)垃圾回收糕簿,HotSpot虛擬機以永久代來實現(xiàn)方法區(qū),從而JVM的垃圾收集器可以像管理堆區(qū)一樣管理這部分區(qū)域狡孔,從而不需要專門為這部分設(shè)計垃圾回收機制懂诗。不過自從JDK7之后,Hotspot虛擬機便將運行時常量池從永久代移除了苗膝⊙旰悖】

jdk1.7開始逐步去永久代。從String.interns()方法可以看出來
String.interns()
native方法:作用是如果字符串常量池已經(jīng)包含一個等于這個String對象的字符串辱揭,則返回代表池中的這個字符串的String對象离唐,在jdk1.6及以前常量池分配在永久代中∥是裕可通過 -XX:PermSize和-XX:MaxPermSize限制方法區(qū)大小亥鬓。

static String base = "test";

/**
 * 方式一:需要全局變量,不需要設(shè)定堆空間大小
 * @param args
 */
public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    for (int i = 0; i < Integer.MAX_VALUE; i++) {
        String str = base + base;
        base = str;
        list.add(str.intern());
    }
}

/**
 * 方式二:需要設(shè)定堆空間大小,不需要全局變量
 */
public static void main(String[] args) {
    //用list保持著引用 防止full gc回收常量池
    List<String> list = new ArrayList<String>();
    int i = 0;
    while (true) {
        list.add(String.valueOf(i++).intern());
    }
}

//以上其中一個即可測試
//如果在jdk1.6環(huán)境下運行 同時限制方法區(qū)大小 將報OOM后面跟著PermGen space說明方法區(qū)OOM域庇,即常量池在永久代
//如果是jdk1.7或1.8環(huán)境下運行 同時限制堆的大小  將報heap space 即常量池在堆中

idea設(shè)置相關(guān)內(nèi)存大小設(shè)置

這邊暫時不用全局的方式,設(shè)置main方法的vm參數(shù)即可
做相關(guān)的設(shè)置,比如說設(shè)定堆大星陡辍(-Xmx5m -Xms5m -XX:-UseGCOverheadLimit)

這邊如果不設(shè)置UseGCOverheadLimit將報java.lang.OutOfMemoryError: GC overhead limit exceeded,
這個錯是因為GC占用了多余98%(默認值)的CPU時間卻只回收了少于2%(默認值)的堆空間听皿。目的是為了讓應(yīng)用終止熟呛,給開發(fā)者機會去診斷問題。一般是應(yīng)用程序在有限的內(nèi)存上創(chuàng)建了大量的臨時對象或者弱引用對象尉姨,從而導(dǎo)致該異常庵朝。雖然加大內(nèi)存可以暫時解決這個問題,但是還是強烈建議去優(yōu)化代碼又厉,后者更加有效九府,也可通過UseGCOverheadLimit避免[不推薦,這里是因為測試用覆致,并不能解決根本問題]

jdk8真正開始廢棄永久代,轉(zhuǎn)而使用元空間(Metaspace)

java虛擬機對方法區(qū)比較寬松昔逗,除了跟堆一樣可以不存在連續(xù)的內(nèi)存空間,定義空間和可擴展空間篷朵,還可以選擇不實現(xiàn)垃圾收集勾怒。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末婆排,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子笔链,更是在濱河造成了極大的恐慌段只,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鉴扫,死亡現(xiàn)場離奇詭異赞枕,居然都是意外死亡,警方通過查閱死者的電腦和手機坪创,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門炕婶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人莱预,你說我怎么就攤上這事柠掂。” “怎么了依沮?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵涯贞,是天一觀的道長。 經(jīng)常有香客問我危喉,道長宋渔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任辜限,我火速辦了婚禮皇拣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘薄嫡。我一直安慰自己审磁,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布岂座。 她就那樣靜靜地躺著态蒂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪费什。 梳的紋絲不亂的頭發(fā)上钾恢,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機與錄音鸳址,去河邊找鬼瘩蚪。 笑死,一個胖子當(dāng)著我的面吹牛稿黍,可吹牛的內(nèi)容都是我干的疹瘦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼巡球,長吁一口氣:“原來是場噩夢啊……” “哼言沐!你這毒婦竟也來了邓嘹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤险胰,失蹤者是張志新(化名)和其女友劉穎汹押,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體起便,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡棚贾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了榆综。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妙痹。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖鼻疮,靈堂內(nèi)的尸體忽然破棺而出怯伊,到底是詐尸還是另有隱情,我是刑警寧澤陋守,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站利赋,受9級特大地震影響水评,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜媚送,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一中燥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧塘偎,春花似錦疗涉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至涵防,卻和暖如春闹伪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背壮池。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工偏瓤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人椰憋。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓厅克,卻偏偏與公主長得像,于是被迫代替她去往敵國和親橙依。 傳聞我的和親對象是個殘疾皇子证舟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,500評論 2 359