JVM从入门到放弃——JVM内存模型
前言
Java和C或者是C++相比較而言,最大的區(qū)別是C系列的程序員在編寫代碼的時候,總是要對程序中的變量進(jìn)行釋放內(nèi)存的操作,所以在編寫C或者是C++的程序員需要格外的謹(jǐn)慎,因?yàn)樗麄儗Τ绦虻膬?nèi)存有著很高的權(quán)限,這樣雖然是特點(diǎn)但是同時也是缺點(diǎn),畢竟every coin has two sides。所以跟Java語言相比而言,Java把內(nèi)存的管理直接交付給JVM,因?yàn)镴VM的存在,Java程序員能夠更關(guān)注業(yè)務(wù)的實(shí)現(xiàn),而不需要對內(nèi)存的管理過于關(guān)注。但是我們在編程的時候,有時候會出現(xiàn)OutOfMemoryError之類的錯誤,這就是JVM內(nèi)存溢出的錯誤。這樣如果我們對Java虛擬機(jī)對內(nèi)存的管理,我們就不能很好的解決類似的問題,所以我們還是要對Java的內(nèi)存管理要有一定的理解,對我們后期對Java代碼調(diào)優(yōu)也是有一定的幫助。
Java虛擬機(jī)內(nèi)存模型
?
根據(jù)上圖可以看出來JVM的運(yùn)行時數(shù)據(jù)區(qū)域主要就是方法區(qū),虛擬機(jī)棧,虛擬機(jī)堆內(nèi)存,本地方法區(qū)和程序計(jì)數(shù)器。下面就來看看這些個內(nèi)存區(qū)域都是用來存儲哪些數(shù)據(jù)的。
Java虛擬機(jī)棧
方法區(qū)是線程私有的內(nèi)存區(qū)域,聲明周期與線程相同。虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型,每個方法執(zhí)行的時候,虛擬機(jī)會以棧幀的形式壓入到棧中,這里的棧也是一種先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu)。棧幀通常是用來存儲局部變量表,操作數(shù)棧,幀數(shù)據(jù)區(qū)等信息。每個方法的調(diào)用和結(jié)束都是入棧和出棧的操作。由于每次方法的調(diào)用都會生成對應(yīng)的棧幀,棧幀會占用一定的棧空間,因此,如果棧幀的空間不足,函數(shù)的調(diào)用就無法進(jìn)行下去,當(dāng)請求的棧的深度大于最大的可用棧深度的時候,系統(tǒng)就會拋出StackOverflowError的溢出錯誤。?
局部變量表存放編譯期可以知道的各種基本數(shù)據(jù)類型(boolean,byte,char,short,int,float,long,double),對象引用和returnAddress類型。其中64位長度的long和double類型的數(shù)據(jù)會占用2個slot局部變量空間,其余的都是一個slot。局部變量表所需要的內(nèi)存空間在編譯期間完成分配,運(yùn)行期間不會改變局部變量表的大小。?
代碼實(shí)現(xiàn)StackOverflowError的溢出錯誤
在運(yùn)行的時候,修改JVM參數(shù),通過修改-Xss128K可以改變虛擬機(jī)棧的大小,我第一次是128K第二次是256K,看執(zhí)行的結(jié)果
遞歸java棧的深度是 : 994 Exception in thread "main" java.lang.StackOverflowError at java.lang.Integer.<init>(Unknown Source) at java.lang.Integer.valueOf(Unknown Source) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:8) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
第二次
遞歸java棧的深度是 : 2475 Exception in thread "main" java.lang.StackOverflowError at java.lang.Integer.<init>(Unknown Source) at java.lang.Integer.valueOf(Unknown Source) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:8) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
在eclipse改變JVM的參數(shù)操作?
?
<————————-這是分隔符————————————->?
本地方法棧
本地方法棧和虛擬機(jī)棧類似,但是他們也是有區(qū)別的,區(qū)別就是虛擬機(jī)棧是調(diào)用java方法的時候,會把棧幀壓入棧中,而本地方法棧是調(diào)用的native方法,native是由C++編寫的。同時本地方法棧也會和虛擬機(jī)棧一樣也是會爆出來StackOverflowError和OutOfMemoryError的錯誤。OutOfMemoryError的錯誤是在虛擬機(jī)的棧內(nèi)存可以自動擴(kuò)展的情況下,不停的將棧幀數(shù)據(jù)壓入到棧中,以至于虛擬機(jī)不停的申請內(nèi)存,最后導(dǎo)致內(nèi)存的溢出,所以爆出來OutOfMemoryError錯誤。
虛擬機(jī)堆
Java Heap是Java虛擬機(jī)所管理的內(nèi)存最大的一塊,這一塊的內(nèi)存區(qū)域是所有線程共享的。此內(nèi)存區(qū)域是用來存放對象實(shí)例,幾乎所有的對象實(shí)例以及數(shù)組都在這里分配內(nèi)存。Java Heap還可以細(xì)分為新生代區(qū)和老年代區(qū),而新生代區(qū)還可以分為eden區(qū),from區(qū)和to區(qū),from和to的大小是一樣的。在絕大數(shù)的情況下,對象是先分配在eden區(qū),在第一次垃圾回收后,如果對象還存活著,那么該對象就會進(jìn)入到from區(qū)或者是to區(qū),然后每經(jīng)過一次垃圾回收,對象依然存活著,它的年紀(jì)就會增加1。當(dāng)對象的年紀(jì)到達(dá)一定的條件后,該對象就會進(jìn)入到老年tenured區(qū)。
程序計(jì)數(shù)器
Program Counter是每個線程的私有空間,Java虛擬機(jī)會為每一個線程創(chuàng)建PC寄存器,在任意時刻,一個線程總是在執(zhí)行一個方法,正在執(zhí)行的方法稱為當(dāng)前方法。如果當(dāng)前方法不是本地方法,PC寄存器就會指向當(dāng)前正在被執(zhí)行的指令。如果當(dāng)前方法是本地方法,那么PC寄存器的值就是undefined。
方法區(qū)
方法區(qū)也是線程共享的內(nèi)存區(qū)域,用于保存系統(tǒng)的類信息,比如類的字段,方法,常量池等,方法區(qū)的大小決定了系統(tǒng)可以保存多少個類如果系統(tǒng)定義了太多的類,同樣會導(dǎo)致方法區(qū)的溢出。在JDK1.6和JDK1.7中,方法區(qū)可以理解為永久區(qū)(Perm)。永久區(qū)可以使用參數(shù)-XX:PermSize和-XX:MaxPermSize指定,默認(rèn)情況下,-XX:MaxPermSize為64MB。一個大的永久區(qū)可以保存更多的信息。如果系統(tǒng)中使用一些動態(tài)代理,那么就有可能在運(yùn)行時生成大量的類。在JDK1.8中,永久區(qū)已經(jīng)被徹底移除,用元數(shù)據(jù)區(qū)來代替。元數(shù)據(jù)區(qū)可以使用-XX:MaxMetaspaceSize指定,元數(shù)據(jù)區(qū)使用的系統(tǒng)的直接內(nèi)存。如果不指定元數(shù)據(jù)的大小,程序會耗盡所有的內(nèi)存。
package com.jvm.perm;import net.sf.cglib.beans.BeanGenerator;public class PermTest { class Perm{ String name; public String getName(www.bomaoyule.cn) { return name; } public void setName(String name) { this.name = name; } } public static void main(String[www.yingka178.com?] args) { try { for (int i = 0; i < 1000000; i++) { BeanGenerator generator = new BeanGenerator(www.078881.cn?); generator.setSuperclass(Perm.class); generator.addProperty("name", String.class); generator.create(www.chaoyueyule.com/); } } catch (Exception www.dongfan178.com e) www.mcyllpt.com/?{ // TODO: handle exception加了虛擬機(jī)參數(shù)-XX:+PrintGCDetails -XX:MaxMetaspaceSize=256k?
運(yùn)行結(jié)果
轉(zhuǎn)載于:https://www.cnblogs.com/qwangxiao/p/9249586.html
總結(jié)
以上是生活随笔為你收集整理的JVM从入门到放弃——JVM内存模型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深度学习的常用框架
- 下一篇: msp430项目编程14