JVM筆記【1】-- 運行時數據區

[TOC]java

(一)java內存區域管理

C/C++每個new操做都須要本身去delete/free,而java裏面有虛擬機自動管理內存,不容易出現內存泄漏或者溢出的問題,可是不容易出現不表明不出現,瞭解虛擬機怎麼使用和管理內存是十分重要的是,對程序優化或者問題排查有幫助。數組

運行時區域主要分爲:數據結構

  • 線程私有:多線程

    • 程序計數器:Program Count Register,線程私有,沒有垃圾回收
    • 虛擬機棧:VM Stack,線程私有,沒有垃圾回收
    • 本地方法棧:Native Method Stack,線程私有,沒有垃圾回收
  • 線程共享:函數

    • 方法區:Method Area,以HotSpot爲例,JDK1.8後元空間取代方法區,有垃圾回收。
    • 堆:Heap,垃圾回收最重要的地方。

image-20201222221827719

1.1 程序計數器

空間很小,當前線程執行的字節碼的行號指示器(線程獨有,指示當前執行到哪,下一步須要執行哪個字節碼),分支,循環,跳轉,異常處理,線程恢復都須要依賴它。
線程私有:java多線程實際上是線程輪流切換並分配處理器執行時間的方式實現,一個核一個具體的時間點,只會執行一個線程的指令。線程切換須要保存和恢復正確的執行位置(保護和恢復現場),因此不一樣的線程須要不一樣的程序計數器。性能

  • 執行java方法時,程序計數器記錄的是正在執行的字節碼指令地址
  • 執行Native方法,程序計數器爲空

惟一一個沒有規定任何OutOfMemory的區域,也沒有GC(垃圾回收)。學習

1.2 虛擬機棧

線程私有,生命週期和線程同樣,主要是記錄該線程Java方法執行的內存模型。虛擬機棧裏面放着好多棧幀。注意虛擬機棧,對應是Java方法,不包括本地方法。
一個Java方法執行會建立一個棧幀,一個棧幀主要存儲:優化

  • 局部變量表
  • 操做數棧
  • 動態連接
  • 方法出口

每個方法調用的時候,就至關於將一個棧幀放到虛擬機棧中(入棧),方法執行完成的時候,就是對應着將該棧幀從虛擬機棧中彈出(出棧)。spa

每個線程有一個本身的虛擬機棧,這樣就不會混起來,若是不是線程獨立的話,會形成調用混亂。線程

你們平時說的java內存分爲堆和棧,其實就是爲了簡便的不太嚴謹的說法,他們說的棧通常是指虛擬機棧,或者虛擬機棧裏面的局部變量表。

局部變量表通常存放着如下數據:

  • 基本數據類型(boolean,byte,char,short,int,float,long,double
  • 對象引用(reference類型,不必定是對象自己,多是一個對象起始地址的引用指針,或者一個表明對象的句柄,或者與對象相關的位置)
  • returAddress(指向了一條字節碼指令的地址)

局部變量表內存大小編譯期間肯定,運行期間不會變化。空間衡量咱們叫Slot(局部變量空間)。64位的long和double會佔用2個Slot,其餘的數據類型佔用1個Slot。

異常:

  • StackOverflowError:線程請求的棧深度大於虛擬機容許的深度
  • OutOfMemoryError:內存不足

1.3 本地方法棧

和虛擬機棧相似,對應本地方法,Native,虛擬機規範容許語言,使用方式和數據結構不一樣,有些可能將虛擬機棧和本地方法棧合併。
異常與虛擬機棧一致:

  • StackOverflowError:線程請求的棧深度大於虛擬機容許的深度
  • OutOfMemoryError:內存不足

1.4 java堆

堆是內存管理最大的一塊,線程共享。

虛擬機規範中說,全部的對象實例和數組都要在堆上分配。可是實際上不是全部的對象都在堆上分配,這個和JIT編譯器的發展和逃逸分析技術相關。Why?
// TODO
堆的細分:新生代,老年代,再細分有Eden,From survivor,To survivor等。

堆中也有可能有線程私有的區域,分配緩衝區。

物理上能夠不連續,可是邏輯上是連續的。

異常:

  • OutOfMemoryError:內存不足

1.5 方法區

名爲非堆,可是實際和堆同樣,是線程共享的區域,主要存貯如下信息:

  • 已被虛擬機加載的類信息
  • 常量
  • 靜態變量
  • 即時編譯器編譯後的代碼

方法區不等於永久代,指示Hotspot虛擬機將GC分代收集拓展到方法區,也就是用永久代實現了方法區,而其餘的虛擬機不必定,不是固定的。JDK1.7將永久代的字符串常量移出了。

方法區回收垃圾的效果不是很好,能夠選擇不回收,虛擬機能夠決定,固然也可能發生內存泄漏。
異常:

  • OutOfMemoryError:內存分配異常

1.5.1 運行時常量池

運行時常量池時方法區的一部分,可是不是所有,Class文件主要包括:

  • 類的版本
  • 字段
  • 方法
  • 接口
  • 常量池,存放編譯產生的字面量和符號引用,通常除了描述Class文件的符號引用,還有直接引用也在裏面。是動態的,運行時能夠產生,好比String.intern()方法。

異常:

  • OutOfMemoryError:內存分配異常

(二)直接內存

不是虛擬機運行時數據區,也不是規範規定的區域,可是使用頻繁且可能會有OutOfMemoryError:內存分配異常出現。
好比,NIO(1.4)基於Channel與Buffer的I/O,能夠用Native函數直接分配堆外內存,經過存儲在Java堆中的DirectByteBuffer對象做爲引用來操做,提升性能,不須要Java堆和Native堆都來回複製數據。

直接內存受物理的內存,或者處理器尋址空間之類的限制。

本文系JVM學習相關筆記,整理來自周志明老師的《深刻理解Java虛擬機》,無比欽佩,強烈推薦!

【做者簡介】
秦懷,公衆號【秦懷雜貨店】做者,技術之路不在一時,山高水長,縱使緩慢,馳而不息。這個世界但願一切都很快,更快,可是我但願本身能走好每一步,寫好每一篇文章,期待和大家一塊兒交流。

此文章僅表明本身(本菜鳥)學習積累記錄,或者學習筆記,若有侵權,請聯繫做者覈實刪除。人無完人,文章也同樣,文筆稚嫩,在下不才,勿噴,若是有錯誤之處,還望指出,感激涕零~

相關文章
相關標籤/搜索