這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)如何理解Java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)域,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
站在用戶的角度思考問題,與客戶深入溝通,找到蘆山網(wǎng)站設(shè)計(jì)與蘆山網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個性化、用戶體驗(yàn)好的作品,建站類型包括:成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名與空間、雅安服務(wù)器托管、企業(yè)郵箱。業(yè)務(wù)覆蓋蘆山地區(qū)。一、程序計(jì)數(shù)器(Program Counter Register)
當(dāng)前線程所執(zhí)行的字節(jié)碼行號指示器(邏輯)
通過改變計(jì)數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令
和線程一對一的關(guān)系,即“線程私有”
對 Java 方法計(jì)數(shù),如果是 Native 方法則計(jì)數(shù)器值為 Undefined
只是計(jì)數(shù),不會發(fā)生內(nèi)存泄漏
每個 Java 方法在執(zhí)行的同時(shí)會創(chuàng)建一個棧幀用于存儲局部變量表、操作數(shù)棧、常量池引用等信息。從方法調(diào)用直至執(zhí)行完成的過程,就對應(yīng)著一個棧幀在 Java 虛擬機(jī)棧中入棧和出棧的過程。
可以通過 -Xss 這個虛擬機(jī)參數(shù)來指定每個線程的 Java 虛擬機(jī)棧內(nèi)存大?。?/p>
java -Xss512M HackTheJava
該區(qū)域可能拋出以下異常:
當(dāng)線程請求的棧深度超過大值,會拋出 StackOverflowError 異常;
棧進(jìn)行動態(tài)擴(kuò)展時(shí)如果無法申請到足夠內(nèi)存,會拋出 OutOfMemoryError 異常。
局部變量表和操作數(shù)棧
局部變量表:包含方法執(zhí)行過程中的所有變量
操作數(shù)棧:入棧、出棧、復(fù)制、交換、產(chǎn)生消費(fèi)變量
public class JVMTest { public static int add(int a ,int b) { int c = 0; c = a + b; return c; } }
javap -verbose JVMTest
本地方法棧與 Java 虛擬機(jī)棧類似,它們之間的區(qū)別只不過是本地方法棧為本地方法服務(wù)。
本地方法一般是用其它語言(C、C++ 或匯編語言等)編寫的,并且被編譯為基于本機(jī)硬件和操作系統(tǒng)的程序,對待這些方法需要特別處理。
所有對象都在這里分配內(nèi)存,是垃圾收集的主要區(qū)域(”GC 堆”)。
現(xiàn)代的垃圾收集器基本都是采用分代收集算法,其主要的思想是針對不同類型的對象采取不同的垃圾回收算法??梢詫⒍逊殖蓛蓧K:
新生代(Young Generation)
老年代(Old Generation)
堆不需要連續(xù)內(nèi)存,并且可以動態(tài)增加其內(nèi)存,增加失敗會拋出 OutOfMemoryError 異常。
可以通過 -Xms 和 -Xmx 這兩個虛擬機(jī)參數(shù)來指定一個程序的堆內(nèi)存大小,第一個參數(shù)設(shè)置初始值,第二個參數(shù)設(shè)置大值。
java -Xms1M -Xmx2M HackTheJava
1. Java 內(nèi)存分配策略
靜態(tài)存儲:編譯時(shí)確定每個數(shù)據(jù)目標(biāo)在運(yùn)行時(shí)的存儲空間需求
棧式存儲:數(shù)據(jù)區(qū)需求在編譯時(shí)未知,運(yùn)行時(shí)模塊入口前確定
堆式存儲:編譯時(shí)或運(yùn)行時(shí)模塊入口都無法確定,動態(tài)分配
2. 問題一:堆和棧的聯(lián)系
引用對象、數(shù)組時(shí),棧里定義變量保存堆中目標(biāo)的首地址。
3. 問題二:棧和堆的區(qū)別
①. 物理地址
堆的物理內(nèi)存分配是不連續(xù)的;
棧的物理內(nèi)存分配是連續(xù)的
②. 分配內(nèi)存
堆是不連續(xù)的,分配的內(nèi)存是在運(yùn)行期確定的,大小不固定;
棧是連續(xù)的,分配的內(nèi)存在編譯器就已經(jīng)確定,大小固定
③. 存放內(nèi)容
堆中存放的是對象和數(shù)組,關(guān)注的是數(shù)據(jù)的存儲;
棧中存放局部變量,關(guān)注的是程序方法的執(zhí)行
④. 是否線程私有
堆內(nèi)存中的對象對所有線程可見,可被所有線程訪問;
棧內(nèi)存屬于某個線程私有的
⑤. 異常
棧擴(kuò)展失敗,會拋出 StackOverflowError;
堆內(nèi)存不足,會拋出 OutOfMemoryError
用于存放已被加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。
和堆一樣不需要連續(xù)的內(nèi)存,并且可以動態(tài)擴(kuò)展,動態(tài)擴(kuò)展失敗一樣會拋出 OutOfMemoryError 異常。
對這塊區(qū)域進(jìn)行垃圾回收的主要目標(biāo)是對常量池的回收和對類的卸載,但是一般比較難實(shí)現(xiàn)。
HotSpot 虛擬機(jī)把它當(dāng)成永久代來進(jìn)行垃圾回收。但很難確定永久代的大小,因?yàn)樗艿胶芏嘁蛩赜绊懀⑶颐看?Full GC 之后永久代的大小都會改變,所以經(jīng)常會拋出 OutOfMemoryError 異常。為了更容易管理方法區(qū),從 JDK 1.8 開始,移除永久代,并把方法區(qū)移至元空間,它位于本地內(nèi)存中,而不是虛擬機(jī)內(nèi)存中。
方法區(qū)是一個 JVM 規(guī)范,永久代與元空間都是其一種實(shí)現(xiàn)方式。在 JDK 1.8 之后,原來永久代的數(shù)據(jù)被分到了堆和元空間中。元空間存儲類的元信息,靜態(tài)變量和常量池等放入堆中。
1. 元空間(MetaSpace)與永久代(PermGen)的區(qū)別
元空間使用本地內(nèi)存,而永久代使用 JVM 的內(nèi)存。
2. 元空間(MetaSpace)相比永久代(PermGen)的優(yōu)勢
字符串常量池存在永久代中,容易出現(xiàn)性能問題和內(nèi)存溢出
類和方法的信息大小難以確定,給永久代的大小指定帶來困難
永久代會為 GC 帶來不必要的復(fù)雜性
運(yùn)行時(shí)常量池是方法區(qū)的一部分。
Class 文件中的常量池(編譯器生成的字面量和符號引用)會在類加載后被放入這個區(qū)域。
除了在編譯期生成的常量,還允許動態(tài)生成,例如 String 類的 intern()。
直接內(nèi)存
在 JDK 1.4 中新引入了 NIO 類,它可以使用 Native 函數(shù)庫直接分配堆外內(nèi)存,然后通過 Java 堆里的 DirectByteBuffer 對象作為這塊內(nèi)存的引用進(jìn)行操作。這樣能在一些場景中顯著提高性能,因?yàn)楸苊饬嗽诙褍?nèi)存和堆外內(nèi)存來回拷貝數(shù)據(jù)。
上述就是小編為大家分享的如何理解Java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)域了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司行業(yè)資訊頻道。