jvm运行时数据区是干啥的?CPU切换线程会不会突然忘记程序执行到哪一步了
目錄
還是那張JVM總體圖
線程
程序計(jì)數(shù)器(PC寄存器)
使用PC寄存器存儲(chǔ)字節(jié)碼指令地址有什么用呢?為什么使用PC寄存器記錄當(dāng)前線程的執(zhí)行地址呢?
PC寄存器為什么會(huì)被設(shè)定為線程私有?
CPU時(shí)間片
還是那張JVM總體圖
? ? 內(nèi)存是非常重要的系統(tǒng)資源,是硬盤和CPU的中間倉庫及橋梁,承載著操作系統(tǒng)和應(yīng)用程序的實(shí)時(shí)運(yùn)行。JVM內(nèi)存布局規(guī)定了Java在運(yùn)行過程中內(nèi)存申請(qǐng)、分配、管理的策略,保證了JVM的高效穩(wěn)定運(yùn)行。不同的JVM對(duì)于內(nèi)存的劃分方式和管理機(jī)制存在著部分差異。結(jié)合JVM虛擬機(jī)規(guī)范,來探討一下經(jīng)典的JVM內(nèi)存布局。
? ? Java虛擬機(jī)定義了若干種程序運(yùn)行期間會(huì)使用到的運(yùn)行時(shí)數(shù)據(jù)區(qū),其中有一些會(huì)隨著虛擬機(jī)啟動(dòng)而創(chuàng)建,隨著虛擬機(jī)退出而銷毀。另外一些則是與線程一一對(duì)應(yīng)的,這些與線程對(duì)應(yīng)的數(shù)據(jù)區(qū)域會(huì)隨著線程開始和結(jié)束而創(chuàng)建和銷毀。
? ? 灰色的為單獨(dú)線程私有的,紅色的為多個(gè)線程共享的。即:
? ? 每個(gè)線程:獨(dú)立包括程序計(jì)數(shù)器、棧、本地棧。線程間共享:堆、堆外內(nèi)存(永久代或元空間、代碼緩存)。
線程
? ? 1.線程是一個(gè)程序里的運(yùn)行單元。JVM允許一個(gè)應(yīng)用有多個(gè)線程并行的執(zhí)行。
? ? 2.在HotSpot JVM里,每個(gè)線程都與操作系統(tǒng)的本地線程直接映射。當(dāng)一個(gè)Java線程準(zhǔn)備好執(zhí)行以后,此時(shí)一個(gè)操作系統(tǒng)的本地線程也同時(shí)創(chuàng)建,Java線程執(zhí)行終止后,本地線程也會(huì)回收。
? ? 3.操作系統(tǒng)負(fù)責(zé)所有線程的安排調(diào)度到任何一個(gè)可用的CPU上。一旦本地線程初始化成功,它就會(huì)調(diào)用Java線程中的run()方法。
? ? 4.守護(hù)線程也叫精靈線程, 當(dāng)程序只剩下 守護(hù)線程的時(shí)候 程序就會(huì)退出。守護(hù)線程的作用 類似在后臺(tái)靜默執(zhí)行,比如JVM的垃圾回收機(jī)制, 這個(gè)就是一個(gè) 守護(hù)線程。 而非守護(hù)線程則不會(huì)。
? ? 如果使用jconsole或者是任何一個(gè)調(diào)試工具,都能看到在后臺(tái)有許多線程在運(yùn)行。這些后臺(tái)線程不包括調(diào)用main方法的main線程以及所有這個(gè)main線程自己創(chuàng)建的線程。
? ? 這些主要的后臺(tái)系統(tǒng)線程在Hotspot JVM里主要是以下幾個(gè):
? ? 1.虛擬機(jī)線程:這種線程的操作是需要JVM達(dá)到安全點(diǎn)才會(huì)出現(xiàn)。這些操作必須在不同的線程中發(fā)生的原因是他們都需要JVM達(dá)到安全點(diǎn),這樣堆才不會(huì)變化。這種線程的執(zhí)行類型包括“stop-hte-world”的垃圾收集,線程棧收集,線程掛起以及偏向鎖撤銷。
? ? 2.周期任務(wù)線程:這種線程是時(shí)間周期事件的體現(xiàn)(比如中斷),他們一般用于周期性操作的調(diào)度執(zhí)行。
? ? 3.GC線程:這種線程對(duì)在JVM里不同種類的垃圾收集行為提供了支持。
? ? 4.編譯線程:這種線程在運(yùn)行時(shí)會(huì)將字節(jié)碼編譯成到本地代碼。
? ? 5.信號(hào)調(diào)度線程:這種線程接收信號(hào)并發(fā)送給JVM,在它內(nèi)部通過調(diào)用適當(dāng)?shù)姆椒ㄟM(jìn)行處理。
程序計(jì)數(shù)器(PC寄存器)
? ? JVM中的程序計(jì)數(shù)寄存器(program Counter Register)中,Register的命名源于CPU的寄存器,寄存器存儲(chǔ)指令相關(guān)的現(xiàn)場(chǎng)信息。CPU只有把數(shù)據(jù)裝載到寄存器才能夠運(yùn)行。
? ? 這里,并非廣義上所指的物理寄存器,或許將其翻譯為PC計(jì)數(shù)器(或指令計(jì)數(shù)器)會(huì)更加貼切(也成為程序鉤子),并且也不容易引起一些不必要的誤會(huì)。JVM中的PC寄存器是對(duì)物理PC寄存器的一種抽象模擬。
作用:
? ? PC寄存器用來存儲(chǔ)指向下一條指令的地址,也即將要執(zhí)行的指令代碼。由執(zhí)行引擎讀取下一條指令。
? ? 它是一塊很小的內(nèi)存空間,幾乎可以忽略不計(jì),也是運(yùn)行速度最快的存儲(chǔ)區(qū)域。
? ? 在JVM規(guī)范中,每個(gè)線程都有它自己的程序計(jì)數(shù)器,是線程私有的,生命周期與線程的生命周期保持一致。
? ? 任何時(shí)間一個(gè)線程都只有一個(gè)方法在執(zhí)行,也就是所謂的當(dāng)前方法。程序計(jì)數(shù)器會(huì)存儲(chǔ)當(dāng)前線程正在執(zhí)行的Java方法的JVM指令地址;或者,如果是在執(zhí)行native方法,則是未指定值(undefined)。
? ? 它是程序控制流的指示器,分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個(gè)計(jì)數(shù)器來完成。
? ? 字節(jié)碼解釋器工作時(shí)就是通過改變這個(gè)計(jì)數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令。
? ? 它是唯一一個(gè)在Java虛擬機(jī)規(guī)范中沒有規(guī)定任何OutOfMemoryError情況的區(qū)域。
使用PC寄存器存儲(chǔ)字節(jié)碼指令地址有什么用呢?為什么使用PC寄存器記錄當(dāng)前線程的執(zhí)行地址呢?
? ? 因?yàn)镃PU需要不停的切換各個(gè)線程,這時(shí)候切換回來以后,就得知道接著從哪開始繼續(xù)執(zhí)行。
? ? JVM的字節(jié)碼解釋器就需要通過改變PC寄存器的值來明確下一條應(yīng)該執(zhí)行什么樣的字節(jié)碼指令。
PC寄存器為什么會(huì)被設(shè)定為線程私有?
? ? 我們都知道所謂的多線程在一個(gè)特定的時(shí)間段內(nèi)只會(huì)執(zhí)行其中某一個(gè)線程的方法,CPU會(huì)不停地做任務(wù)切換,這樣必然導(dǎo)致經(jīng)常中斷或恢復(fù),如何保證分毫無差呢?為了能夠準(zhǔn)確地記錄各個(gè)線程正在執(zhí)行的當(dāng)前字節(jié)碼指令地址,最好的辦法自然是為每一個(gè)線程都分配一個(gè)PC寄存器,這樣一來各個(gè)線程之間便可以進(jìn)行獨(dú)立計(jì)算,從而不會(huì)出現(xiàn)相互干擾的情況。
? ? 由于CPU時(shí)間片輪限制,眾多線程在并發(fā)執(zhí)行過程中,任何一個(gè)確定的時(shí)刻,一個(gè)處理器或者多核處理器中的一個(gè)內(nèi)核,只會(huì)執(zhí)行某個(gè)線程的一條指令。
? ? 這樣必然導(dǎo)致經(jīng)常中斷或恢復(fù),如何保證分毫無差呢?每個(gè)線程在創(chuàng)建后,都會(huì)產(chǎn)生自己的程序計(jì)數(shù)器和棧幀,程序計(jì)數(shù)器在各個(gè)線程之間互不影響。
CPU時(shí)間片
? ? CPU時(shí)間片即CPU分配給各個(gè)程序的時(shí)間,每個(gè)線程被分配一個(gè)時(shí)間段,稱作它的時(shí)間片。
? ? 在宏觀上:我們可以同時(shí)打開多個(gè)應(yīng)用程序,每個(gè)程序并行不悖,同時(shí)運(yùn)行。
? ? 在微觀上:由于只有一個(gè)CPU,一次只能處理程序要求的一部分,如何處理公平,一種方法就是引入時(shí)間片,每個(gè)程序輪流執(zhí)行。
總結(jié)
以上是生活随笔為你收集整理的jvm运行时数据区是干啥的?CPU切换线程会不会突然忘记程序执行到哪一步了的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java类是如何加载的?不知道class
- 下一篇: 你只知道JVM栈,知不知道栈帧、局部变量