Java虛擬機的內(nèi)存結(jié)構(gòu)是怎樣的

本篇內(nèi)容主要講解“Java虛擬機的內(nèi)存結(jié)構(gòu)是怎樣的”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“Java虛擬機的內(nèi)存結(jié)構(gòu)是怎樣的”吧!

創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供平山網(wǎng)站建設(shè)、平山做網(wǎng)站、平山網(wǎng)站設(shè)計、平山網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、平山企業(yè)網(wǎng)站模板建站服務(wù),十余年平山做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。

一:簡介

內(nèi)存(Memory)也被稱為內(nèi)存儲器,其作用是用于暫時存放CPU中的運算數(shù)據(jù),以及與硬盤等外部存儲器交換的數(shù)據(jù)。只要計算機在運行中,CPU就會把需要運算的數(shù)據(jù)調(diào)到內(nèi)存中進行運算,當(dāng)運算完成后CPU再將結(jié)果傳送出來。

Java虛擬機在執(zhí)行Java程序過程中會把它所管理的內(nèi)存劃分為若干個不同的數(shù)據(jù)區(qū)域。這些區(qū)域都有各自的用途,以及創(chuàng)建和銷毀的時間,有的區(qū)域隨著虛擬機進程的啟動而存在,有些區(qū)域則依賴用戶線程的啟動和結(jié)束而建立和銷毀。

進程:一段程序的執(zhí)行過程,是一個具有一定獨立功能的程序關(guān)于某個數(shù)據(jù)集合的一次運行活動。它是操作系統(tǒng)動態(tài)執(zhí)行的基本單元,在傳統(tǒng)的操作系統(tǒng)中,進程既是基本的分配單元,也是基本的執(zhí)行單元。

進程是一個實體。每一個進程都有它自己的地址空間,一般情況下,包括文本區(qū)域(text region)、數(shù)據(jù)區(qū)域(data region)和堆棧(stack region)。文本區(qū)域存儲處理器執(zhí)行的代碼;數(shù)據(jù)區(qū)域存儲變量和進程執(zhí)行期間使用的動態(tài)分配的內(nèi)存;堆棧區(qū)域存儲著活動過程調(diào)用的指令和本地變量。第二,進程是一個“執(zhí)行中的程序”。程序是一個沒有生命的實體,只有處理器賦予程序生命時,它才能成為一個活動的實體,我們稱其為進程。

進程有三個狀態(tài),就緒、運行和阻塞。就緒狀態(tài)其實就是獲取了出cpu外的所有資源,只要處理器分配資源就可以馬上執(zhí)行。就緒狀態(tài)有排隊序列什么的,排隊原則不再贅述。運行態(tài)就是獲得了處理器分配的資源,程序開始執(zhí)行。阻塞態(tài),當(dāng)程序條件不夠時候,需要等待條件滿足時候才能執(zhí)行,如等待i/o操作時候,此刻的狀態(tài)就叫阻塞態(tài)。

線程:通常在一個進程中可以包含若干個線程,當(dāng)然一個進程中至少有一個線程,不然沒有存在的意義。線程可以利用進程所擁有的資源,在引入線程的操作系統(tǒng)中,通常都是把進程作為分配資源的基本單位,而把線程作為獨立運行和獨立調(diào)度的基本單位,由于線程比進程更小,基本上不擁有系統(tǒng)資源,故對它的調(diào)度所付出的開銷就會小得多,能更高效的提高系統(tǒng)多個程序間并發(fā)執(zhí)行的程度。

進程和線程的主要差別:在于它們是不同的操作系統(tǒng)資源管理方式。進程有獨立的地址空間,一個進程崩潰后,在保護模式下不會對其它進程產(chǎn)生影響,而線程只是一個進程中的不同執(zhí)行路徑。線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等于整個進程死掉,所以多進程的程序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些

Java虛擬機的內(nèi)存結(jié)構(gòu)是怎樣的

二:程序計數(shù)器

  1. 程序計數(shù)器是一塊較小的內(nèi)存空間,它可以看作是當(dāng)前線程執(zhí)行的字節(jié)碼行號的指示器。

  2. 字節(jié)碼解釋器工作時就是通過改變這個計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令;分支,循環(huán),跳轉(zhuǎn),異常處理,線程恢復(fù)等基礎(chǔ)功能都需要依賴這個計數(shù)器來完成

  3. 當(dāng)線程獲得時間片處于執(zhí)行過程時,CPU會按照程序計數(shù)器中存儲的內(nèi)容依次的取出指令執(zhí)行,當(dāng)CPU取出當(dāng)前指令時,CPU自動修改程序計數(shù)器內(nèi)容,使其指向下一條指令字節(jié)碼行號。由于程序計數(shù)器中存儲的是數(shù)字值,因此不會隨著程序運行而擴大需求空間,故不會發(fā)生溢出。

  4. 假設(shè)線程A正在執(zhí)行,當(dāng)執(zhí)行到某個階段,優(yōu)先級更高線程B執(zhí)行。此時,線程A掛起,線程B執(zhí)行。當(dāng)線程B執(zhí)行完畢后,需要喚醒線程A繼續(xù)執(zhí)行,那么如何從線程A的中斷位置繼續(xù)執(zhí)行呢,那就需要CPU訪問線程A的程序計數(shù)器,從中獲取下一條執(zhí)行指令,保證程序繼續(xù)執(zhí)行。由于每個線程需要保存自身的執(zhí)行位置,也就使得程序計數(shù)器為線程私有。

  5. native本地方法大多是通過C實現(xiàn)并未編譯成需要執(zhí)行的字節(jié)碼指令,所以在計數(shù)器中是undefined

  6. 這個內(nèi)存區(qū)域是唯一一個在java虛擬界規(guī)范中沒有規(guī)定任何OutOfMemoryError的情況的區(qū)域

三:Java虛擬機棧

  1. 它是一個后入先出的棧,其中保存的元素是棧幀 。它也是線程私有的,它的生命周期與線程相同。

  2. 程序運行時,每調(diào)用一個方法就會生成一個棧幀,同時將當(dāng)前正在執(zhí)行方法的棧幀壓入虛擬機棧。虛擬機棧頂?shù)臈瑸椤爱?dāng)前活躍棧幀”。既然棧幀是調(diào)用方法時創(chuàng)建,那么其保存內(nèi)容必然與方法息息相關(guān)。

    局部變量表:局部變量表是一組局部變量值存儲空間,用于存放方法參數(shù)和方法內(nèi)部定義的局部變量。局部變量表存放了編譯器可知的各種基本數(shù)據(jù)類型,對象引用和returnAddress類型。局部變量表的內(nèi)存是在編譯期間完成分配,當(dāng)進入一個方法時,這個方法需要在幀中分配多大的局部變量空間是完全確定的,在方法運行期間不會改變局部變量表的大小。

操作數(shù)棧:操作數(shù)棧是一個以字長為單位的數(shù)組。但它不是通過索引來訪問,而是通過標(biāo)準(zhǔn)的棧操作—壓棧和出?!獊碓L問的。比如,如果某個指令A(yù)把一個值1壓入到操作數(shù)棧中,指令B將值2壓入棧中,稍后指令C就可以彈出這兩個個值來進行相加計算,并將結(jié)果3壓入棧中。通過操作數(shù)??梢酝瓿煞椒ㄖ械囊恍┻\算。

動態(tài)鏈接:每個棧幀內(nèi)部都包含一個指向當(dāng)前方法所在類型的運行時常量池的引用,以便對當(dāng)前方法的代碼實現(xiàn)動態(tài)鏈接。在class文件里面,一個方法如果要調(diào)用另外一個方法,或者訪問其成員變量,則需要通過符號引用來表示,那么動態(tài)鏈接的作用就是在恰當(dāng)?shù)臅r候?qū)⑦@些以符號引用所表示的方法或是變量解析成直接引用。

返回地址:一般來說,方法正常退出時,調(diào)用者PC計數(shù)器的值就可以作為返回地址,棧幀中很可能會保存這個計數(shù)器值。而方法異常退出時,返回地址是要通過異常處理器來確定的,棧幀中一般不會保存這部分信息。 方法退出的過程實際上等同于把當(dāng)前棧幀出棧,因此退出時可能執(zhí)行的操作有:恢復(fù)上層方法的局部變量表和操作數(shù)棧,把返回值(如果有的話)壓入調(diào)用棧幀的操作數(shù)棧中,調(diào)用PC計數(shù)器的值以指向方法調(diào)用指令后面的一條指令等。

其他信息:虛擬機規(guī)范允許具體的虛擬機實現(xiàn)增加一些規(guī)范里沒有描述的信息到棧幀中,例如與高度相關(guān)的信息,這部分信息完全取決于具體的虛擬機實現(xiàn)。

3.如果線程請求的棧深度大于虛擬機所允許的深度,將拋出StackOverflowError異常; 如果虛擬機??梢詣討B(tài)擴展,如果擴展時無法申請到足夠的內(nèi)存,就會拋出OutOfMemoryError異常。

四:本地方法棧

  1. 本地方法棧與虛擬機棧所發(fā)揮的作用是非常相似的,它們之間的區(qū)別不過是虛擬機棧是為虛擬機執(zhí)行Java方法服務(wù),而本地方法棧則為虛擬機使用到的Native方法服務(wù)。

  2. 本地方法棧區(qū)域也會拋出StackOverflowError和OutOfMemoryError異常。

五:Java堆

  1. Java堆是被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機啟動時創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這里分配內(nèi)存。

  2. Java堆一般分為三大部分:新生代,老年代和永久代

新生代:主要是用來存放新生的對象。一般占據(jù)堆的1/3空間。由于頻繁創(chuàng)建對象,所以新生代會頻繁觸發(fā)MinorGC進行垃圾回收。

老年代:主要存放應(yīng)用程序中生命周期長的內(nèi)存對象。老年代的對象比較穩(wěn)定,所以MajorGC不會頻繁執(zhí)行。在進行MajorGC前一般都先進行了一次MinorGC,使得有新生代的對象晉身入老年代,導(dǎo)致空間不夠用時才觸發(fā)。當(dāng)無法找到足夠大的連續(xù)空間分配給新創(chuàng)建的較大對象時也會提前觸發(fā)一次MajorGC進行垃圾回收騰出空間。

永久代:指內(nèi)存的永久保存區(qū)域,主要存放Class和Meta(元數(shù)據(jù))的信息,Class在被加載的時候被放入永久區(qū)域. 它和和存放實例的區(qū)域不同,GC不會在主程序運行期對永久區(qū)域進行清理。所以這也導(dǎo)致了永久代的區(qū)域會隨著加載的Class的增多而脹滿,最終拋出OOM異常。

  1. Java堆是垃圾收集器管理的主要區(qū)域。

  2. Java堆可以處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上是連續(xù)的即可。

  3. 可以通過-Xmx和-Xms來擴展,如果無法再擴展時,將會拋出OutOfMemoryError異常

六:方法區(qū)

  1. 方法區(qū)與Java堆一樣,是各個線程共享的內(nèi)存區(qū)域,它用于存儲已被虛擬機加載的類信息,常量,靜態(tài)變量,即時編譯器編譯后的代碼等數(shù)據(jù)。

  2. 當(dāng)方法區(qū)無法滿足內(nèi)存分配需求時,將拋出OutOfMemoryError異常

到此,相信大家對“Java虛擬機的內(nèi)存結(jié)構(gòu)是怎樣的”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

標(biāo)題名稱:Java虛擬機的內(nèi)存結(jié)構(gòu)是怎樣的
分享鏈接:http://bm7419.com/article8/jjceip.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營銷型網(wǎng)站建設(shè)動態(tài)網(wǎng)站、定制網(wǎng)站、定制開發(fā)、網(wǎng)站制作、自適應(yīng)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站