本篇文章給大家分享的是有關(guān)Java運(yùn)行時(shí)的數(shù)據(jù)區(qū)有哪些,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
10年積累的成都網(wǎng)站建設(shè)、成都做網(wǎng)站經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有分宜免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
JVM體系結(jié)構(gòu)和運(yùn)行時(shí)數(shù)據(jù)區(qū)概述
要理解JVM的運(yùn)行時(shí)數(shù)據(jù)區(qū), 必須先要理解JVM的體系結(jié)構(gòu), 因?yàn)樘摂M機(jī)的體系結(jié)構(gòu)基本上解釋了“為什么會(huì)有這些運(yùn)行時(shí)數(shù)據(jù)區(qū)” 。 JVM的體系結(jié)構(gòu)如下:
由此可見, 運(yùn)行時(shí)數(shù)據(jù)區(qū)的劃分, 是和JVM的體系結(jié)構(gòu)相關(guān)的。 本文主要介紹運(yùn)行時(shí)數(shù)據(jù)區(qū)的劃分, 對(duì)體系結(jié)構(gòu)不做深入的講解。 簡單概括一下, 類加載器子系統(tǒng)用于將class文件加載到虛擬機(jī)的運(yùn)行時(shí)數(shù)據(jù)區(qū)中(準(zhǔn)確的說應(yīng)該是方法區(qū)) 。 可以認(rèn)為執(zhí)行引擎是字節(jié)碼的執(zhí)行機(jī)制, 一個(gè)線程可以看做是一個(gè)執(zhí)行引擎的實(shí)例。 下面介紹運(yùn)行時(shí)數(shù)據(jù)區(qū):
JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)
方法區(qū)
在字面意思上, “方法區(qū)”這個(gè)詞會(huì)讓人產(chǎn)生誤解。因?yàn)榉椒▍^(qū)存放的不只是方法, 它存放的是類型信息。我們在寫程序的時(shí)候, 幾乎總是在和類, 對(duì)象打交道, 我們知道根據(jù)一個(gè)類可以創(chuàng)建對(duì)象。 一般來說, 我們操縱的是對(duì)象, 訪問對(duì)象的屬性, 調(diào)用對(duì)象的方法等, 但是我們要思考這樣一個(gè)問題, 虛擬機(jī)根據(jù)什么信息知道如何創(chuàng)建對(duì)象的呢? 當(dāng)然是根據(jù)這個(gè)對(duì)象的類型信息, 但是這個(gè)類型信息在哪里呢?現(xiàn)在我們知道是在方法區(qū)中。 那么類型信息是被誰加載到方法區(qū)中的呢?由上面的體系結(jié)構(gòu)圖, 我們可以知道是類加載器子系統(tǒng)?那么所謂的類型信息, 都包含什么信息呢?這些信息又是如何存放的呢?這里的類型信息, 可以籠統(tǒng)的認(rèn)為就是我們前面講解過的一個(gè)class文件,類加載器子系統(tǒng)將會(huì)提取class文件里面的類型信息,并將這些類型信息存放到方法區(qū)中。 至于方法區(qū)中如何存放一個(gè)類型數(shù)據(jù), 是和JVM的具體實(shí)現(xiàn)相關(guān)的。 但是不管如何實(shí)現(xiàn), 一個(gè)類的類型信息總是會(huì)包含如下信息:
類的全限定名
當(dāng)前類的直接父類的全限定名
這個(gè)類是接口類型, 類類型, 還是枚舉類型
類的訪問修飾符信息
當(dāng)前類型的超接口的全限定名
當(dāng)前類型的常量池
字段信息
方法信息
如果對(duì)class文件格式比較熟悉的話, 可以看出, 這些信息都是在class文件中描述過的。 由于我們無法看到類型信息具體是如何存儲(chǔ)的, 但是大致可以將類型信息看做一個(gè)class文件, 這有助于我們的理解。下面再次列出class文件結(jié)構(gòu)的表格,讀者可以對(duì)比class文件中的內(nèi)容到類型數(shù)據(jù)上, 該表中的各種數(shù)據(jù)已經(jīng)在前面的博客中詳細(xì)講解過:
類型數(shù)據(jù)中,除了這些基本信息外, 類型信息還包括以下兩個(gè)方面:
一個(gè)到類的ClassLoader對(duì)象的引用
一個(gè)到表示該類的Class實(shí)例對(duì)象的引用
靜態(tài)變量存儲(chǔ)區(qū)
由于之前的博客中詳細(xì)介紹過class文件的格式, 對(duì)上面的一些基本信息我們可能比較熟悉, 但是對(duì)這兩種信息就比較陌生了。 其實(shí)說來也簡單,每個(gè)class都是被一個(gè)類加載器加載到方法區(qū)的, 類型信息中的到類的ClassLoader對(duì)象的引用, 表明了當(dāng)前的類是被哪個(gè)類加載器加載的, 這個(gè)信息同時(shí)也標(biāo)示了當(dāng)前的類型的名稱空間。
每當(dāng)一個(gè)class文件被成功的加載到方法區(qū)中, JVM總會(huì)創(chuàng)建一個(gè)Class對(duì)象, 來唯一標(biāo)示這個(gè)類。 這個(gè)Class對(duì)象可以看做是類加載過程的產(chǎn)物, 由于它描述了整個(gè)類型信息, 而Java中的反射也是針對(duì)的類型信息, 所以這個(gè)Class對(duì)象是反射的基石, 大多數(shù)反射API都是根據(jù)Class對(duì)象來實(shí)現(xiàn)的。
而靜態(tài)變量也是存在于類型信息中, 可以這么說, 類型信息中, 會(huì)有專門的區(qū)域存放類的靜態(tài)變量。 與存在于對(duì)象中的實(shí)例變量不同, 靜態(tài)變量存在于類型數(shù)據(jù)中, 每個(gè)類型只有一份,所以也叫類變量。
方法區(qū)是一個(gè)相對(duì)來說比較固定的內(nèi)存區(qū), 因?yàn)樗娣诺氖穷愋托畔ⅲ?而類型信息在被加載到方法區(qū)中之后, 除了必要的連接和初始化, 一般不會(huì)有較大改動(dòng),一般情況下, JVM也不會(huì)卸載類型信息, 所以方法區(qū)也可以稱為JVM的靜態(tài)區(qū)。 一個(gè)類型的生命周期一般就是整個(gè)程序的生命周期。 這也是為什么要慎用靜態(tài)變量的原因所在, 因?yàn)殪o態(tài)變量隨類型信息存放在方法區(qū)中, 生命周期很長, 如果使用不當(dāng), 很容易造成內(nèi)存泄露。 一個(gè)JVM實(shí)例中只存在一個(gè)方法區(qū), 方法區(qū)中的所有類型數(shù)據(jù)被所有線程共享。
堆
方法區(qū)是存放類型數(shù)據(jù)的, 而堆則是存放運(yùn)行時(shí)產(chǎn)生的對(duì)象的。 和C++不同的是, Java只能在堆中存放對(duì)象, 而不能在棧上分配對(duì)象, 所有運(yùn)行時(shí)產(chǎn)生的對(duì)象全部都存放于堆中, 包括數(shù)組。 我們知道, 在Java中, 數(shù)組也是對(duì)象。一個(gè)JVM實(shí)例中只有一個(gè)堆, 所有線程共享堆中的數(shù)據(jù)(對(duì)象) 。
Java虛擬機(jī)支持幾種不同的創(chuàng)建對(duì)象的指令, 如new , anewarray等。 這些指令執(zhí)行的結(jié)果就是在堆中分配內(nèi)存, 并創(chuàng)建對(duì)象。 但是Java虛擬機(jī)的指令集中并不包含任何釋放內(nèi)存的指令, 因而我們也就不能手動(dòng)釋放內(nèi)存。 所有被創(chuàng)建的對(duì)象都會(huì)被一個(gè)叫做垃圾收集器(GC)的模塊自動(dòng)回收, 垃圾收集器有不同的實(shí)現(xiàn)方式, 他們以 特定的方式判斷對(duì)象是否過期, 并以特定的方式對(duì)對(duì)象進(jìn)行回收, 關(guān)于垃圾收集的話題不是本文的重點(diǎn), 這里就不多說了。 我們只要知道:所有創(chuàng)建的對(duì)象都存在堆中, 而垃圾收集器會(huì)自動(dòng)回收過期的對(duì)象, 所以,JVM的堆區(qū)是垃圾收集器的“重點(diǎn)管理區(qū)” 。
Java棧
Java棧是一個(gè)線程的執(zhí)行區(qū)域, 它保存著一個(gè)線程中的方法的調(diào)用狀態(tài), 也可以說, 一個(gè)Java線程的運(yùn)行狀態(tài), 都由一個(gè)Java棧來保存。 在這個(gè)棧中, 每一方法對(duì)應(yīng)一個(gè)棧幀, 請注意區(qū)分棧幀和棧這兩個(gè)概念。 棧指的是整個(gè)線程的執(zhí)行棧, 棧幀是棧中的一個(gè)單位, 每個(gè)方法對(duì)應(yīng)一個(gè)棧幀。 JVM會(huì)對(duì)Java棧執(zhí)行兩種操作: 壓棧和出棧。 這兩種操作在執(zhí)行時(shí)都是以幀(棧幀)為單位的。 當(dāng)調(diào)用了一個(gè)新的方法, 就會(huì)壓入一個(gè)棧幀, 當(dāng)一個(gè)方法調(diào)用完成, 就會(huì)彈出這個(gè)方法的棧幀, 回到調(diào)用者的棧幀。
舉例來說, 如果方法a調(diào)用了方法b, 而方法b中調(diào)用了方法c。 這個(gè)過程中的方法調(diào)用和返回的裝狀態(tài)是這樣的(其中圖中兩條虛線之間表示Java棧,每個(gè)方塊表示一個(gè)特定方法的棧幀)
Java棧上的所有數(shù)據(jù)都是線程私有的, 也就是說, 每個(gè)線程都會(huì)有自己的Java棧, 不會(huì)相互訪問其他Java棧中的數(shù)據(jù)。
PC寄存器
pc寄存器用于存放一條指令的地址, 這條指令就是虛擬機(jī)要執(zhí)行的下一條指令。pc寄存器和線程相關(guān)聯(lián), 每一個(gè)線程都有一個(gè)PC寄存器。
本地方法棧
我們知道Java可以和C/C++互調(diào)。如果當(dāng)前線程執(zhí)行的代碼是C/C++寫的本地代碼, 那么這些方法就在本地方法棧中執(zhí)行,而不會(huì)在Java棧中執(zhí)行, Java棧中只執(zhí)行Java方法。
以上就是Java運(yùn)行時(shí)的數(shù)據(jù)區(qū)有哪些,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識(shí)。更多詳情敬請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。