java三年,Java开发三年,你不得不了解的JVM(一)
基本概念:
JVM 是可運行 Java 代碼的假想計算機 ,包括一套字節(jié)碼指令集、一組寄存器、一個棧、一個垃圾回收,堆 和 一個存儲方法域。JVM 是運行在操作系統(tǒng)之上的,它與硬件沒有直接的交互。
運行過程:
我們都知道
Java
源文件,通過編譯器,能夠生產(chǎn)相應的
.Class
文件,也就是字節(jié)碼文件,
而字節(jié)碼文件又通過
Java
虛擬機中的解釋器,編譯成特定機器上的機器碼。
也就是如下:
①
Java
源文件—
->
編譯器—
->
字節(jié)碼文件
②字節(jié)碼文件—
->JVM
—
->
機器碼
每一種平臺的解釋器是不同的,但是實現(xiàn)的虛擬機是相同的,這也就是
Java
為什么能夠
跨平臺的原因了,當一個程序從開始運行,這時虛擬機就開始實例化了,多個程序啟動就會
存在多個虛擬機實例。程序退出或者關閉,則虛擬機實例消亡,多個虛擬機實例之間數(shù)據(jù)不
能共享。
線程
這里所說的線程指程序執(zhí)行過程中的一個線程實體。JVM允許一個應用并發(fā)執(zhí)行多個線程。Hotspot JVM 中的Java 線程與原生操作系統(tǒng)線程有直接的映射關系。當線程本地存儲、緩沖區(qū)分配、同步對象、棧、程序計數(shù)器等準備好以后,就會創(chuàng)建一個操作系統(tǒng)原生線程。Java 線程結束,原生線程隨之被回收。操作系統(tǒng)負責調(diào)度所有線程,并把它們分配到任何可用的CPU 上。當原生線程初始化完畢,就會調(diào)用Java 線程的run() 方法。當線程結束時,會釋放原生線程和Java 線程的所有資源。
HotspotJVM
后臺運行的系統(tǒng)線程主要有下面幾個:
JVM內(nèi)存區(qū)域
JVM 內(nèi)存區(qū)域主要分為線程私有區(qū)域【程序計數(shù)器、虛擬機棧、本地方法區(qū)】、線程共享區(qū)域【JAVA堆、方法區(qū)】、直接內(nèi)存。
線程私有數(shù)據(jù)區(qū)域生命周期與線程相同, 依賴用戶線程的啟動/結束而創(chuàng)建/銷毀(在Hotspot VM內(nèi), 每個線程都與操作系統(tǒng)的本地線程直接映射, 因此這部分內(nèi)存區(qū)域的存/否跟隨本地線程的生/死對應)。線程共享區(qū)域隨虛擬機的啟動/關閉而創(chuàng)建/銷毀。直接內(nèi)存并不是JVM運行時數(shù)據(jù)區(qū)的一部分,但也會被頻繁的使用: 在JDK 1.4引入的NIO提供了基于Channel與Buffer的IO方式, 它可以使用Native函數(shù)庫直接分配堆外內(nèi)存, 然后使用DirectByteBuffer對象作為這塊內(nèi)存的引用進行操作(詳見:Java I/O 擴展), 這樣就避免了在Java堆和Native堆中來回復制數(shù)據(jù), 因此在一些場景中可以顯著提高性能。
程序計數(shù)器(線程私有)
一塊較小的內(nèi)存空間, 是當前線程所執(zhí)行的字節(jié)碼的行號指示器,每條線程都要有一個獨立的程序計數(shù)器,這類內(nèi)存也稱為“線程私有”的內(nèi)存。
正在執(zhí)行
java
方法的話,計數(shù)器記錄的是虛擬機字節(jié)碼指令的地址(當前指令的地址)。如
果還是
Native
方法,則為空。
這個內(nèi)存區(qū)域是唯一一個在虛擬機中沒有規(guī)定任何
OutOfMemoryError
情況的區(qū)域。
虛擬機棧(線程私有)
是描述java方法執(zhí)行的內(nèi)存模型,每個方法在執(zhí)行的同時都會創(chuàng)建一個棧幀(StackFrame)用于存儲局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口等信息。每一個方法從調(diào)用直至執(zhí)行完成的過程,就對應著一個棧幀在虛擬機棧中入棧到出棧的過程。
棧幀(Frame)是用來存儲數(shù)據(jù)和部分過程結果的數(shù)據(jù)結構,同時也被用來處理動態(tài)鏈接(Dynamic Linking)、方法返回值和異常分派(Dispatch Exception)。棧幀隨著方法調(diào)用而創(chuàng)建,隨著方法結束而銷毀——無論方法是正常完成還是異常完成(拋出了在方法內(nèi)未被捕獲的異常)都算作方法結束。
本地方法區(qū)(線程私有)
本地方法區(qū)和Java Stack作用類似, 區(qū)別是虛擬機棧為執(zhí)行Java方法服務, 而本地方法棧則為Native方法服務,如果一個VM實現(xiàn)使用C-linkage模型來支持Native調(diào)用,那么該棧將會是一個C棧,但HotSpot VM直接就把本地方法棧和虛擬機棧合二為一。
堆(Heap-線程共享)-運行時數(shù)據(jù)區(qū)
是被線程共享的一塊內(nèi)存區(qū)域,創(chuàng)建的對象和數(shù)組都保存在Java堆內(nèi)存中,也是垃圾收集器進行垃圾收集的最重要的內(nèi)存區(qū)域。由于現(xiàn)代VM采用分代收集算法,因此Java堆從GC的角度還可以細分為:新生代(Eden區(qū)、From Survivor區(qū)和To Survivor區(qū))和老年代。
方法區(qū)/永久代(線程共享)
即我們常說的
永久代
(Permanent Generation)
,
用于存儲
被
JVM
加載的類信息
、
常量
、
靜
態(tài)變量
、
即時編譯器編譯后的代碼
等數(shù)據(jù)
.HotSpotVM
把
GC
分代收集擴展至方法區(qū)
,
即
使用
Java
堆的永久代來實現(xiàn)方法區(qū)
,
這樣
HotSpot
的垃圾收集器就可以像管理
Java
堆一樣管理這部分內(nèi)存
,
而不必為方法區(qū)開發(fā)專門的內(nèi)存管理器
(
永久帶的內(nèi)存回收的主要目標是針對
常量池的回收
和
類型
的卸載
,
因此收益一般很小
)
。
運行時常量池
(
Runtime Constant Pool
)是方法區(qū)的一部分。
Class
文件中除了有類的版
本、字段、方法、接口等描述等信息外,還有一項信息是常量池
(
Constant Pool Table
),用于存放編譯期生成的各種字面量和符號引用,這部分內(nèi)容將在類加
載后存放到方法區(qū)的運行時常量池中。
Java
虛擬機對
Class
文件的每一部分(自然也包括常量
池)的格式都有嚴格的規(guī)定,每一個字節(jié)用于存儲哪種數(shù)據(jù)都必須符合規(guī)范上的要求,這樣才會
被虛擬機認可、裝載和執(zhí)行。
總結
以上是生活随笔為你收集整理的java三年,Java开发三年,你不得不了解的JVM(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Can I insert a count
- 下一篇: Intellij IDEA 快捷键整理(