JVM学习笔记:Java运行时数据区域
JVM執(zhí)行Java程序的過程中,會(huì)使用到各種數(shù)據(jù)區(qū)域,這些區(qū)域有各自的用途、創(chuàng)建和銷毀時(shí)間。根據(jù)《Java虛擬機(jī)規(guī)范》,JVM包括下列幾個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)域,如下圖所示:
其中紅色部分是線程私有的,即每個(gè)線程各自都有自己的一份。綠色部分是各個(gè)線程共享的。
1.PC寄存器(The pc Register)
(1)每一個(gè)Java線程都有一個(gè)PC寄存器。
(2)PC寄存器是用于存儲(chǔ)每個(gè)線程下一步將執(zhí)行的JVM指令,如該方法為native的,則PC寄存器中不存儲(chǔ)任何信息。
(3)此內(nèi)存區(qū)域是唯一一個(gè)在JVM Spec中沒有規(guī)定任何OutOfMemoryError情況的區(qū)域。
2.JVM棧(Java Virtual Machine Stacks)
(1)JVM棧是線程私有的,每個(gè)線程創(chuàng)建的同時(shí)都會(huì)創(chuàng)建JVM棧,與程PC寄存器一樣,JVM棧的生命周期也是與線程相同。
(2)JVM棧中存放的為當(dāng)前線程中局部基本類型的變量(Java中定義的八種基本類型:boolean、char、byte、short、int、long、float、double)、部分的返回結(jié)果以及Stack Frame,非基本類型的對(duì)象在JVM棧上僅存放一個(gè)指向堆上的地址。
(3)在JVM Spec中對(duì)這個(gè)區(qū)域規(guī)定了兩種異常狀況:如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度,將拋出StackOverflowError異常;如果JVM棧可以動(dòng)態(tài)擴(kuò)展(JVM Spec中允許固定長度的JVM棧),當(dāng)擴(kuò)展時(shí)無法申請(qǐng)到足夠內(nèi)存則拋出OutOfMemoryError異常。
(4)由于JVM棧是線程私有的,因此其在內(nèi)存分配上非常高效,并且當(dāng)線程運(yùn)行完畢后,這些內(nèi)存也就被自動(dòng)回收。
3.本地方法棧(Native Method Stacks)
(1)本地方法棧與JVM棧所發(fā)揮作用是類似的,只不過JVM棧為虛擬機(jī)運(yùn)行JVM原語服務(wù),而本地方法棧是為虛擬機(jī)使用到的Native方法服務(wù)。它的實(shí)現(xiàn)的語言、方式與結(jié)構(gòu)并沒有強(qiáng)制規(guī)定,甚至有的虛擬機(jī)(譬如Sun Hotspot虛擬機(jī))直接就把本地方法棧和JVM棧合二為一。
(2)和JVM棧一樣,這個(gè)區(qū)域也會(huì)拋出StackOverflowError和OutOfMemoryError異常。
4.方法區(qū)(Method Area)
(1)別名叫做Non-Heap(非堆)。
(2)方法區(qū)域存放了所加載的類的信息(名稱、修飾符等)、類中的靜態(tài)變量、類中定義為final類型的常量、類中的Field信息、類中的方法信息,當(dāng)開發(fā)人員在程序中通過Class對(duì)象中的getName、isInterface等方法來獲取信息時(shí),這些數(shù)據(jù)都來源于方法區(qū)域。
(3)方法區(qū)域是全局共享的,在一定的條件下它也會(huì)被GC,當(dāng)方法區(qū)域需要使用的內(nèi)存超過其允許的大小時(shí),會(huì)拋出OutOfMemory的錯(cuò)誤信息。
(4)在Sun JDK中這塊區(qū)域?qū)?yīng)的為Permanet Generation,又稱為永久代,默認(rèn)為64M,可通過-XX:PermSize以及-XX:MaxPermSize來指定其大小。
5.運(yùn)行時(shí)常量池(Runtime Constant Pool)
(1)類似C中的符號(hào)表,存放的為類中的固定的常量信息、方法和Field的引用信息等,其空間從方法區(qū)域中分配。
(2)Class文件中除了有類的版本、字段、方法、接口等描述等信息外,還有一項(xiàng)信息是常量表(constant_pool table),用于存放編譯期已可知的常量,這部分內(nèi)容將在類加載后進(jìn)入方法區(qū)(永久代)存放。但是Java語言并不要求常量一定只有編譯期預(yù)置入Class的常量表的內(nèi)容才能進(jìn)入方法區(qū)常量池,運(yùn)行期間也可將新內(nèi)容放入常量池(最典型的String.intern()方法)。
(3)運(yùn)行時(shí)常量池是方法區(qū)的一部分,自然受到方法區(qū)內(nèi)存的限制,當(dāng)常量池?zé)o法在申請(qǐng)到內(nèi)存時(shí)會(huì)拋出OutOfMemoryError異常。
?
6.Java堆(Java Heap)
Java堆是被所有線程共享的,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。它是JVM用來存儲(chǔ)對(duì)象實(shí)例以及數(shù)組值的區(qū)域,絕大部分的對(duì)象實(shí)例都在這里分配。在逃逸分析和標(biāo)量替換優(yōu)化技術(shù)出現(xiàn)后,并不是所有的對(duì)象實(shí)例都是在這里分配,但我們可以粗略地認(rèn)為Java中所有通過new創(chuàng)建的對(duì)象的內(nèi)存都在此分配。Heap中的對(duì)象的內(nèi)存需要等待GC進(jìn)行回收。
?
大小通過-Xms和-Xmx來控制,-Xms為JVM啟動(dòng)時(shí)申請(qǐng)的最小Heap內(nèi)存(默認(rèn)為物理內(nèi)存的1/64但小于1G),-Xmx為JVM可申請(qǐng)的最大Heap內(nèi)存(默認(rèn)為物理內(nèi)存的1/4)。默認(rèn)當(dāng)空余堆內(nèi)存小于40%時(shí),JVM會(huì)增大Heap的大小到-Xmx指定的大小,可通過-XX:MinHeapFreeRatio=來指定這個(gè)比例。 默認(rèn)當(dāng)空余堆內(nèi)存大于70%時(shí),JVM會(huì)將Heap的大小往-Xms指定的大小調(diào)整,可通過-XX:MaxHeapFreeRatio=來指定這個(gè)比例。但對(duì)于運(yùn)行系統(tǒng)而言,為了避免頻繁的Heap Size的調(diào)整,通常都會(huì)將-Xms和-Xmx的值設(shè)成一樣,因此這兩個(gè)用于調(diào)整比例的參數(shù)通常是沒用的。
?
JVM將Heap分為New Generation和Old Generation(或Tenured Generation)兩塊來進(jìn)行管理:
(1)New Generation
又稱為新生代,程序中新建的對(duì)象都將分配到新生代中,新生代又由Eden Space和兩塊Survivor Space構(gòu)成,可通過-Xmn參數(shù)來指定其大小。發(fā)生在新生代的垃圾收集動(dòng)作稱為Minor GC。
(2)Old Generation
又稱為舊生代(老年代),用于存放程序中經(jīng)過幾次垃圾回收還存活的對(duì)象,例如緩存的對(duì)象等,舊生代所占用的內(nèi)存大小即為-Xmx指定的大小減去-Xmn指定的大小。發(fā)生在老年代的垃圾收集動(dòng)作成為Major?GC/Full GC。
(3)內(nèi)存分配策略
a. 對(duì)象優(yōu)先在Eden分配。b. 大對(duì)象直接進(jìn)入老年代。c. 長期存活的對(duì)象將進(jìn)入老年代。
對(duì)堆的解釋:
1)堆是JVM中所有線程共享的,因此在其上進(jìn)行對(duì)象內(nèi)存的分配均需要進(jìn)行加鎖,這也導(dǎo)致了new對(duì)象的開銷是比較大的。
2)鑒于上面的原因,Sun Hotspot JVM為了提升對(duì)象內(nèi)存分配的效率,對(duì)于所創(chuàng)建的線程都會(huì)分配一塊獨(dú)立的空間,這塊空間又稱為TLAB(Thread Local Allocation Buffer),其大小由JVM根據(jù)運(yùn)行的情況計(jì)算而得,在TLAB上分配對(duì)象時(shí)不需要加鎖,因此JVM在給線程的對(duì)象分配內(nèi)存時(shí)會(huì)盡量的在TLAB上分配,在這種情況下JVM中分配對(duì)象內(nèi)存的性能和C基本是一樣高效的,但如果對(duì)象過大的話則仍然是直接使用堆空間分配。
3)TLAB僅作用于新生代的Eden Space,因此在編寫Java程序時(shí),通常多個(gè)小的對(duì)象比大的對(duì)象分配起來更加高效,但這種方法同時(shí)也帶來了兩個(gè)問題,一是空間的浪費(fèi),二是對(duì)象內(nèi)存的回收上仍然沒法做到像Stack那么高效,同時(shí)也會(huì)增加回收時(shí)的資源的消耗,可通過在啟動(dòng)參數(shù)上增加-XX:+PrintTLAB來查看TLAB這塊的使用情況。
?
參考資料
《深入java虛擬機(jī):VM高級(jí)特性與最佳實(shí)踐》
JVM內(nèi)存管理:深入Java內(nèi)存區(qū)域與OOM?http://icyfenix.iteye.com/blog/802573
http://itindex.net/detail/48698-jvm-%E5%86%85%E5%AD%98
深入理解JVM—JVM內(nèi)存模型 ?http://yhjhappy234.blog.163.com/blog/static/316328322011101723933875/?suggestedreading&wumii
《The Java? Virtual Machine Specification》?http://docs.oracle.com/javase/specs/jvms/se8/html/index.html
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/tsiangleo/p/4403781.html
總結(jié)
以上是生活随笔為你收集整理的JVM学习笔记:Java运行时数据区域的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android学习一:文件操作
- 下一篇: Java异常处理和常用类