一、JVM給JAVA應用程序帶來的影響:
1、一次編寫 到處運行
2、相對安全的內存管理和訪問機制,避免了絕大多數的內存泄露和指針越界問題
c、c++等語言需要自己去爲對象申請內存,同時主動維護其生命週期,而JAVA在JVM的自動內存管理機制下,不需要爲每個new操作去寫配對的free或者delete操作,而是交給JVM自動管理,因此不容易出現內存泄露和內存溢出等問題。但是一旦出現,排查難度就比較大了。
二、JAVA虛擬機運行時數據區的劃分
JAVA虛擬機運行時數據區分爲以下幾個部分:
方法區、虛擬機棧、本地方法棧、堆、程序計數器
其中在某些jvm實現中本地方法棧和虛擬機棧是合二爲一的
1、程序計數器
- 一塊較小的內存空間
- 當前線程所執行字節碼的行號指示器
- 線程私有的內存區域:
jvm的多線程是通過輪流切換並分配處理器時間來實現的,所以在一個確切時刻,一個處理器(對於多核處理器而言是一個內核)都會執行一條線程中的指令。因此,爲了線程切換後可以恢復到正確的執行位置,每個線程都需要有一個獨立的程序計數器 唯一一個java虛擬機規範中沒有規定任何OutOfMemoryError的內存區域
程序計數器中記錄的值:如果線程正在執行一個java方法,那麼程序計數器記錄的是正在執行的虛擬機字節碼指令的地址,如果正在執行的是一個native方法, 則計數器的值爲空。
2、JAVA虛擬機棧
線程私有的內存區域
- 生命週期與線程相同
描述java方法執行的內存模型,每個方法在執行的同時都會創建一個棧幀,用於存儲局部變量表,操作數,動態鏈接,方法出口等信息。每個方法在調用直到完成的過程,就對應一個棧幀在虛擬機棧中從入棧到出棧的過程。
局部變量表存放了編譯器可知的各種基本數據類型(int、double…..)、對象的引用、returnAddress類型(指向一條字節碼指令的地址)。 其中64位長度的long和double數據會佔用2個局部變量空間(slot),而其他數據類型只佔用一個局部變量空間。
局部變量表所需內存空間在編譯期間完成分配,方法運行期間並不會改變局部變量表的大小java虛擬機棧規定的兩種異常:
StackOverFlowError 如果線程請求的棧深度大於虛擬機所允許的棧的深度
- OutOfMemoryError 在虛擬機運行動態拓展時, 如果拓展時無法申請到足夠的內存,就會拋出該異常
3、本地方法棧
與虛擬機棧類似,只是虛擬機棧爲java方法服務,本地方法棧爲native方法服務
4、堆
堆是java虛擬機管理的最大一塊內存區域,被所有線程共享。
在虛擬機啓動時創建
唯一目的是用於存放對象實例
堆可以處於物理上不連續的內存空間,只要邏輯上連續的即可
5、方法區
- 被所有線程共享
- 存儲已被虛擬機加載的類信息、常量、靜態變量,即時編譯器編譯後的代碼
- 雖然java虛擬機規範把方法區描述爲堆的一個邏輯部分,但是它有一個別名non-heap,目的是爲了和堆區別開來
- 運行時常量池是方法區的一部分
6、直接內存