摘要:運行時數據區域虛擬機在執行的過程中會把管理的內存劃分為若干個不同的數據區域。方法區的內存收集還是會出現,不過這個區域的內存收集主要是針對常量池的回收和對類型的卸載。當方法區無法滿足內存分配需求時將拋出異常。
運行時數據區域
Java虛擬機在執行Java的過程中會把管理的內存劃分為若干個不同的數據區域。這些區域有各自的用途,以及創建和銷毀的時間,有的區域隨著虛擬機進程的啟動而存在,而有的區域則依賴線程的啟動和結束而創建和銷毀。
程序計數器
程序計數器是一塊較小的區域,它的作用可以看做是當前線程所執行的字節碼的行號指示器。在虛擬機的模型里,字節碼指示器就是通過改變程序計數器的值來指定下一條需要執行的指令。分支,循環等基礎功能就是依賴程序計數器來完成的。
由于java虛擬機的多線程是通過輪流切換并分配處理器執行時間來完成,一個處理器同一時間只會執行一條線程中的指令。為了線程恢復后能夠恢復正確的執行位置,每條線程都需要一個獨立的程序計數器,以確保線程之間互不影響。所以程序計數器是“線程私有”的內存。
如果虛擬機正在執行的是一個Java方法,則計數器指定的是字節碼指令對應的地址,如果正在執行的是一個本地方法,則計數器指定問空undefined。程序計數器區域是Java虛擬機中唯一沒有定義OutOfMemory異常的區域。
Java虛擬機棧
他和程序計數器一樣也是線程私有的,生命周期與線程相同。虛擬機棧描述的是Java方法執行的內存模型:每個方法被執行的時候都會創建一個棧幀用于存儲局部變量表,操作棧,動態鏈接,方法出口等信息。每一個方法被調用的過程就對應一個棧幀在虛擬機棧中從入棧到出棧的過程。
通常所說的虛擬機運行時分為棧和堆,這里的棧指的就是虛擬機棧或者說虛擬機棧中的局部變量表部分。
局部變量表存放了編譯器可知的各種基本數據類型、對象引用和returnAddress類型(指向一條字節碼指令的地址)。局部變量表所需的內存空間在編譯器完成分配,當進入一個方法時這個方法需要在幀中分配多大的內存空間是完全確定的,運行期間不會改變局部變量表的大小。(64為長度的long和double會占用兩個局部變量空間,其他的數據類型占用一個)
Java虛擬機棧可能出現兩種類型的異常:1. 線程請求的棧深度大于虛擬機允許的棧深度,將拋出StackOverflowError。2.虛擬機棧空間可以動態擴展,當動態擴展是無法申請到足夠的空間時,拋出OutOfMemory異常。
本地方法棧
本地方法棧和虛擬機棧基本類似,只不過Java虛擬機棧執行的是Java代碼(字節碼),本地方法棧中執行的是本地方法的服務。本地方法棧中也會拋出StackOverflowError和OutOfMemory異常。
堆
堆是Java虛擬機所管理的內存中最大的一塊。堆是所有線程共享的一塊區域,在虛擬機啟動時創建。堆的唯一目的是存放對象實例,幾乎所有的對象實例都在這里分配,不過隨著JIT編譯器的發展和逃逸技術的成熟,棧上分配和標量替換技術使得這種情況發生著微妙的變化,對上分配正變得不那么絕對。
附:在Java編程語言和環境中,即時編譯器(JIT compiler,just-in-time compiler)是一個把Java的字節碼(包括需要被解釋的指令的程序)轉換成可以直接發送給處理器的指令的程序。當你寫好一個Java程序后,源語言的語句將由Java編譯器編譯成字節碼,而不是編譯成與某個特定的處理器硬件平臺對應的指令代碼(比如,Intel的Pentium微處理器或IBM的System/390處理器)。字節碼是可以發送給任何平臺并且能在那個平臺上運行的獨立于平臺的代碼。
Java堆是垃圾收集器管理的主要區域,所以也稱為“GC堆”。由于現在的垃圾收集器基本上都是采用分代收集算法,所以Java堆還可細分為:新生代和老生代。在細致一點可分為Eden空間,From Survivor空間,To Survivor空間。如果從內存分配的角度看,線程共享的Java堆可劃分出多個線程私有的分配緩沖區。不過無論如何劃分,都與存放內容無關,無論哪個區域,都是用來存放對象實例。細分的目的是為了更好的回收內存或者更快的分配內存。
Java堆可以是物理上不連續的空間,只要邏輯上連續即可,主流的虛擬機都是按照可擴展的方式來實現的。如果當前堆中沒有內存完成對象實例的創建,并且不能在進行內存擴展,則會拋出OutOfMemory異常。
方法區
方法區也是線程共享的區域,用于存儲已經被虛擬機加載的類信息,常量,靜態變量和即時編譯器(JIT)編譯后的代碼等數據。Java虛擬機把方法區描述為堆的一個邏輯分區,不過方法區有一個別名Non-Heap(非堆),用于區別于Java堆區。
Java虛擬機規范對這個區域的限制也非常寬松,除了可以是物理不連續的空間外,也允許固定大小和擴展性,還可以不實現垃圾收集。相對而言,垃圾收集行為在這個區域是比較少出現的(所以常量和靜態變量的定義要多注意)。方法區的內存收集還是會出現,不過這個區域的內存收集主要是針對常量池的回收和對類型的卸載。
一般來說方法區的內存回收比較難以令人滿意。當方法區無法滿足內存分配需求時將拋出OutOfMemoryError異常。
運行時常量池
運行時常量池是方法區的一部分,Class文件中除了有類的版本,字段,方法,接口等信息以外,還有一項信息是常量池用于存儲編譯器生成的各種字面量和符號引用,這部分信息將在類加載后存放到方法區的運行時常量池中。Java虛擬機對類的每一部分(包括常量池)都有嚴格的規定,每個字節用于存儲哪種數據都必須有規范上的要求,這樣才能夠被虛擬機認可,裝載和執行。一般來說,除了保存Class文件中描述的符號引用外,還會把翻譯出來的直接引用也存儲在運行時常量池中。
運行時常量池相對于Class文件常量池的另外一個重要特征是具備動態性,Java虛擬機并不要求常量只能在編譯期產生,也就是并非預置入Class文件常量池的內容才能進入方法區的運行時常量池中,運行期間也可將新的常量放入常量池中。 常量池是方法區的一部分,所以受到內存的限制,當無法申請到足夠內存時會拋出OutOfMemoryError異常。
對象訪問
對象訪問在Java語言中無處不在,即使是最簡單的訪問,也會涉及到Java棧,java堆,方法區這三個最重要的內存區域之間的關聯關系。如下面的代碼:
Object obj = new Object();
假設這段代碼出現在方法體中,那么“Object obj”部分的語義將會反映到Java棧的本地變量表中,作為一個reference類型的數據存在。而“new Object();”部分的語義將會反應到Java堆中,形成一塊存儲Object類型所有實例數據值(Instance Data)的結構化內存,根據具體類型以及虛擬機實現的對象分布的不同,這塊內存的長度是不固定的。另外,在JAVA堆中還必須包含能查找到此對象內存數據的地址信息,這些類型數據則存儲在方法區中。
由于reference類型在Java虛擬機中之規定了指向對象的引用,并沒有規定這個引用要通過哪種方式去定位,以及訪問到Java堆中的對象的具體位置,因此虛擬機實現的對象訪問方式會有所不同。主流的訪問方式有兩種:句柄訪問方式和直接指針。
如果使用句柄訪問方式,Java堆中將會劃分出一塊內存來作為句柄池,reference中存儲的就是對象的地址,而句柄中包含了對象實例數據和類型數據各自的具體地址信息。
如果通過直接指針方式訪問,Java堆對象的布局中就必須考慮如何放置訪問類型數據的相關信息,reference中直接存儲的就是對象的地址。
兩種方式各有優勢,局部訪問方式最大的好處是reference中存放的是穩定的句柄地址,在對象被移動時,只會改變句柄中的實例數據指針,而reference本身不需要被修改。而指針訪問的最大優勢是速度快,它節省了一次指針定位的開銷,由于對象訪問在Java中非常頻繁,一次這類開銷積少成多后也是一項非常可觀的成本。
具體的訪問方式都是有虛擬機指定的,虛擬機Sun HotSpot使用的是直接指針方式,不過從整個軟件開發的范圍來看,各種語言和框架使用句柄訪問方式的情況十分常見。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/64754.html
摘要:看來還是功力不夠,索性拆成了六篇文章,分別從自動內存管理機制類文件結構類加載機制字節碼執行引擎程序編譯與代碼優化高效并發六個方面來做更加細致的介紹。本文先說說虛擬機的自動內存管理機制。在類加載檢查通過后,虛擬機將為新生對象分配內存。 歡迎關注微信公眾號:BaronTalk,獲取更多精彩好文! 書籍真的是常讀常新,古人說「書讀百遍其義自見」還是蠻有道理的。周志明老師的這本《深入理解 Ja...
摘要:運行時數據區域的學習,是學習以及機制的基礎,也是深入理解對象創建及運行過程的前提。了解內存區域劃分,是學習概念的前提。 Java 運行時數據區域的學習,是學習 jvm 以及 GC 機制的基礎,也是深入理解 java 對象創建及運行過程的前提。廢話不多說,直接進入正題: 一張圖總結 showImg(https://segmentfault.com/img/bVOMAn?w=685&h=5...
摘要:堆區堆是虛擬機所管理的內存中最大的一塊,它是被所有線程共享的一塊內存區域,該區域在虛擬機啟動的時候創建。 運行時數據區域 ? ?想要了解jvm,那對其內存分配管理的學習是必不可少的;java虛擬機在執行java程序的時候會把它所管理的內存劃分成若干數據區域。這些區域有著不同的功能、用途、創建/銷毀時間。java虛擬機所分配管理的內存區域如圖1所示 程序計數器 ? ?程序計數器是一塊比較...
摘要:深入理解虛擬機高級特性與最佳實踐第二版讀書筆記與常見面試題總結本節常見面試題介紹下內存區域運行時數據區。運行時數據區域虛擬機在執行程序的過程中會把它管理的內存劃分成若干個不同的數據區域。 《深入理解Java虛擬機:JVM高級特性與最佳實踐(第二版》讀書筆記與常見面試題總結 本節常見面試題: 介紹下Java內存區域(運行時數據區)。 對象的訪問定位的兩種方式。 1 概述 對于Java...
閱讀 1357·2021-11-24 09:39
閱讀 1346·2021-11-04 16:12
閱讀 2686·2021-09-24 09:47
閱讀 3337·2021-09-01 10:50
閱讀 1477·2019-08-30 15:55
閱讀 1423·2019-08-30 15:43
閱讀 642·2019-08-30 11:08
閱讀 3578·2019-08-23 18:33