jvm在執行java程序過(guò)程中會(huì )將管理的內存劃分成若干不同的數據區域,他們分別是程序計數器,堆,方法區,虛擬機棧,本地方法棧。
1.1程序計數器
指令計數器是線(xiàn)程私有的,每個(gè)線(xiàn)程都有獨立的指令計數器,計數器記錄著(zhù)虛擬機正在執行的字節碼的指令地址,分支,循環(huán),跳轉,異常處理和線(xiàn)程恢復等操作都依賴(lài)這個(gè)計數器完成,如果線(xiàn)程執行的native方法,則這個(gè)計數器為空。
1.2虛擬機棧
虛擬機棧是線(xiàn)程私有的,主要用于存放局部變量表,操作棧,動(dòng)態(tài)鏈接,方法出口等信息,由于每個(gè)方法被執行都會(huì )創(chuàng )建對應的線(xiàn)幀,方法被調用到直至完成調用的過(guò)程,實(shí)際對應線(xiàn)幀在操作棧中入棧和出棧的過(guò)程。在java虛擬機規范中,對這個(gè)區域規定了兩種異常情況:如果線(xiàn)程請求的棧深度大于規定的深度,則拋出StackOverFlowError異常;如果虛擬機棧的動(dòng)態(tài)擴展到了無(wú)法申請的足夠內存時(shí)候將拋出OutOfMemberError異常。
1.3本地方法棧
本地方法棧和虛擬棧的功能相似,包括上述2個(gè)異常情況也一樣,區別在于虛擬機棧是為虛擬機執行的java服務(wù),而本地方法棧是為虛擬機使用的Native方法服務(wù)。
1.4堆
堆是內存中最大的區域,并且它是所有線(xiàn)程共享的區域。它的唯一作用就是存放對象實(shí)例,根據jvm規范的規范,它的內存空間可以使不連續的,只要在邏輯上連續的即可。
1.5 方法區
方法區和堆一樣,是被所有線(xiàn)程共享的運行時(shí)區域,它用于存放被虛擬機加載的累信息,常量,靜態(tài)變量,即時(shí)編譯后的代碼等數據,跟堆的情況一樣,當方法區無(wú)法滿(mǎn)足內存分配需求時(shí),也會(huì )拋出OutOfMemberError的異常。
運行時(shí)常量池也屬于方法區的一部分。class文件除了有版本,字段,方法,接口等描述信息外,其中還有信息是常量池,用于存放編譯后的各種字面量和符號引用,這部分將在類(lèi)加載后存放到方法區的常量池中。另外java語(yǔ)言并非要求常量一定一定在編譯期間產(chǎn)生,即是并非預置入的class文件常量池的內存才能進(jìn)入方法區的運行時(shí)常量池,運行期間同樣也能進(jìn)入。
1.6直接內存
直接內存并不屬于虛擬機運行時(shí)的數據區的一部分, 也不是java虛擬機規范中定義的內存區域,但這部分內存被頻繁使用到,并且也會(huì )爆outofmemoryError異常。
在java jdk1.4中加入了NIO類(lèi),引入了基于通道(Channel)與緩沖區(Buffer)的I/O方式,它可以直接使用Native函數分配堆外的內存,然后通過(guò)存儲在java堆中DirectByteBuffer對象作為這塊內存的引用直接操作,這樣避免了java堆和Native堆來(lái)回復制的問(wèn)題,提升了行性能。
2 對象訪(fǎng)問(wèn)
java虛擬機規定了一個(gè)對象變量指向一個(gè)對象的引用,并沒(méi)有定義這個(gè)引用以何種方式去定位,以及訪(fǎng)問(wèn)到j(luò )ava堆的具體位置,所以不同的虛擬機實(shí)現對象訪(fǎng)問(wèn)的方式略有不同,大概主流的分為:句柄和直接指針。
使用句柄訪(fǎng)問(wèn)方式,java堆會(huì )劃出一個(gè)內存區域作為句柄池,對象的變量存儲的就是句柄池的地址,而句柄池中就存放了對象實(shí)例的數據以及對象類(lèi)型信息的地址信息。若使用直接訪(fǎng)問(wèn)方式,對象變量中存儲的直接是對象實(shí)例的數據以及對象類(lèi)型信息的地址信息。
兩種訪(fǎng)問(wèn)方式各有優(yōu)勢,句柄訪(fǎng)問(wèn)的優(yōu)勢在于對象變量可存儲穩定的地址,當對象移動(dòng)時(shí),只需改變句柄池的地址,變量本身無(wú)需修改。直接訪(fǎng)問(wèn)的優(yōu)勢明顯在于訪(fǎng)問(wèn)速度快,sun HotSpot就是采用第二種對象訪(fǎng)問(wèn)方式。
聯(lián)系客服