笔记:Java虚拟机运行时数据区
Java虛擬機在執行Java程序的過程中會把它管的內存劃分為以下若干個不同的區域:
?
1、程序計數器
程序計數器是一塊較小的內存空間,它可以看作是當前線程所執行的字節碼的行號指示器;由于Java虛擬機的多線程是通過線程輪流切換并分配處理器執行時間的方式來實現,在任何一個確定的時刻,一個處理器(對于多核處理器來說是一個內核)都只能執行一個線程中的指令,因此為了線程切換后能恢復到正確的執行位置,每條線程都需要一個獨立的程序計數器來記錄線程之前執行到哪里了。
如果線程正在執行的是一個Java方法,這個計數器記錄的是正在執行的虛擬機字節碼指令地址;如果正在執行的是一個Native方法,這個計數器值則為空(Undefined)。
這個內存區域是唯一一個在Java虛擬機規范中沒有規定任何OutOfMemoryError情況的區域。
是線程私有的內存空間。
?
2、Java虛擬機棧
是線程私有內存空間。
虛擬機棧描述的是Java方法執行的內存模型:每個方法在執行的時候都會創建一個棧幀,用于存儲局部變量表、操作數棧、動態鏈表、方法的出口信息等。每一個方法從調用直到執行完成的過程,就對應這一個棧幀在虛擬機棧中的入棧和出棧。
局部變量表存放了編譯期可知的各種基本數據類型(boolean、byte、char、short、int、float、long、double)、對象引用(reference類型)和returnAddress類型(指向了一條字節碼指令的地址)。其中64位的long和double類型占用兩個局部變量空間,其余數據類型占用1個變量空間。
局部變量表所需的內存空間在編譯期間完成分配,當進入一個方法時,這個方法需要在幀中分配多大的局部變量空間是完全確定的,在方法運行期間是不會改變局部變量表大小的。
在Java虛擬機規范中,這個區域規定了兩種異常情況:一、如果線程請求的棧深度大于虛擬機所允許的深度,將拋出StackOverflowError異常;二、如果虛擬機可動態擴展(當前大部分虛擬機都可以動態擴展),如果擴展時無法申請到足夠的內存,就會拋出OutOfMemoryError異常。
?
3、本地方法棧
本地方法棧和Java虛擬機棧發揮的作用非常相似,Java虛擬機棧是為虛擬機執行Java方法服務的,而本地方法棧是為虛擬機使用Native方法服務的。在虛擬機規范中對本地方法棧使用的語言、使用方式和數據結構沒有強制規定,因此具體的虛擬機可以自由實現。
在HotSpot虛擬機中把虛擬機棧和本地方法棧合二為一。
是線程私有內存空間。
?
4、Java堆
? Java堆是被所有線程共享的一塊內存區域,是Java虛擬機所管理的內存中最大的一塊。在虛擬機啟動的時候創建。
Java程序創建的對象實例幾乎都在這里分配內存;在Java虛擬機規范中描述:所有的對象實例以及數據都要在堆上分配,但是隨著JIT編譯器的發展和逃逸分析技術逐漸成熟,棧上分配、標量替換優化技術將會導致一些微妙的變化發生,所有對象分配都在堆上也漸漸變得不是那么“絕對”了。
Java堆是垃圾收集器管理的主要區域。
Java堆空間還可以分為:新生代和老年代,新生代又可以細分為:Eden空間、From Survivor空間和To Survivor空間。
如果在堆上沒有內存空間可以完成對象實例分配,并且堆也無法再擴展時,將會拋出OutOfMemoryOut異常。
?
5、方法區
方法區也是各個線程共享的內存區域。
方法區用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據。
在HotSpot虛擬機上,GC分代收集擴展到了方法區,或者說使用永久代來實現方法區,這樣可以像管理Java堆內存一樣管理方法區內存,一般GC和老年代GC一起觸發,所以在HotSpot虛擬機中,方法區也被稱為“永久代”。
方法區的內存回收主要是針對常量池的回收和對類型的卸載(不過條件相當苛刻)。
方法區無法滿足內存分配需求時,將拋出OutOfMemoryError異常。
?
6、運行時常量池
運行時常量池是方法區的一部分。
Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息常量池,用于存放編譯器生成的的各種字面常量和符號引用,這部分內容將在類加載后進入方法區的運行時常量池中存放。
運行時常量池相對于Class文件常量池的另外一個重要特性是具備動態性,Java語言并不要求常量一定只有編譯器才產生,運行期間也可能將新的常量放入到常量池中。
當常量池無法申請到內存時將會拋出OutOfMemoryError異常。
?
7、直接內存
直接內存并不是虛擬機運行時數據區的一部分,也不是Java虛擬機規范中定義的內存區域。但是這部分內存也會被平凡的用到,也會出現OutOfMemoryError異常。
JDK1.4引入了NIO類,一種基于通道(channel)與緩沖區(Buffer)的I/O方式,它可以使用Native函數庫直接分配堆外內存,然后通過一個存儲在Java堆中的DirectButeBuffer對象作為這塊內存的引用進行操作。這種方式避免了Java堆和Native堆中來回復制數據,在一些場景中可以顯著提高性能。
?
轉載于:https://www.cnblogs.com/super-jing/p/10786147.html
總結
以上是生活随笔為你收集整理的笔记:Java虚拟机运行时数据区的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【转】漫画:Bitmap算法
- 下一篇: RE validation in Jav