JVM的結(jié)構(gòu)和運行機制是什么?可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
發(fā)展壯大離不開廣大客戶長期以來的信賴與支持,我們將始終秉承“誠信為本、服務(wù)至上”的服務(wù)理念,堅持“二合一”的優(yōu)良服務(wù)模式,真誠服務(wù)每家企業(yè),認真做好每個細節(jié),不斷完善自我,成就企業(yè),實現(xiàn)共贏。行業(yè)涉及生料攪拌車等,在成都網(wǎng)站建設(shè)、全網(wǎng)營銷推廣、WAP手機網(wǎng)站、VI設(shè)計、軟件開發(fā)等項目上具有豐富的設(shè)計經(jīng)驗。
一、java內(nèi)存組成介紹:堆(Heap)
和非堆(Non-heap)
內(nèi)存
按照官方的說法:“Java 虛擬機具有一個堆,堆是運行時數(shù)據(jù)區(qū)域,所有類實例和數(shù)組的內(nèi)存均從此處分配。
堆是在 Java 虛擬機啟動時創(chuàng)建的?!薄霸贘VM中堆之外的內(nèi)存稱為非堆內(nèi)存(Non-heap memory)”??梢钥闯?strong>JVM主要管理兩種類型的內(nèi)存:堆和非堆。
簡單來說堆就是Java代碼可及的內(nèi)存,是留給開發(fā)人員使用的;非堆就是JVM留給 自己用的,所以方法區(qū)、JVM內(nèi)部處理或優(yōu)化所需的內(nèi)存(如JIT編譯后的代碼緩存)、每個類結(jié)構(gòu)(如運行時常數(shù)池、字段和方法數(shù)據(jù))以及方法和構(gòu)造方法 的代碼都在非堆內(nèi)存中。
1.方法區(qū)也稱”永久代” 、“非堆”, 它用于存儲虛擬機加載的類信息、常量、靜態(tài)變量、是各個線程共享的內(nèi)存區(qū)域。默認最小值為16MB,最大值為64MB,可以通過-XX:PermSize
和 -XX:MaxPermSize
參數(shù)限制方法區(qū)的大小。
運行時常量池:是方法區(qū)的一部分,其中的主要內(nèi)容來自于JVM對Class的加載。
Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池,用于存放編譯器生成的各種符號引用,這部分內(nèi)容將在類加載后放到方法區(qū)的運行時常量池中。
2.虛擬機棧
描述的是java 方法執(zhí)行的內(nèi)存模型:每個方法被執(zhí)行的時候 都會創(chuàng)建一個“棧幀”用于存儲局部變量表(包括參數(shù))、操作棧、方法出口等信息。每個方法被調(diào)用到執(zhí)行完的過程,就對應(yīng)著一個棧幀在虛擬機棧中從入棧到出棧的過程。聲明周期與線程相同,是線程私有的。
局部變量表存放了編譯器可知的各種基本數(shù)據(jù)類型(boolean
、byte
、char
、short
、int
、float
、long
、double
)、對象引用(引用指針,并非對象本身),其中64位長度的long和double類型的數(shù)據(jù)會占用2個局部變量的空間,其余數(shù)據(jù)類型只占1個。
局部變量表所需的內(nèi)存空間在編譯期間完成分配,當(dāng)進入一個方法時,這個方法需要在棧幀中分配多大的局部變量是完全確定的,在運行期間棧幀不會改變局部變量表的大小空間。
3.本地方法棧
與虛擬機?;绢愃疲瑓^(qū)別在于虛擬機棧為虛擬機執(zhí)行的java方法服務(wù),而本地方法棧則是為Native方法服務(wù)。
4.堆
也叫做java 堆、GC堆是java虛擬機所管理的內(nèi)存中最大的一塊內(nèi)存區(qū)域,也是被各個線程共享的內(nèi)存區(qū)域,在JVM啟動時創(chuàng)建。該內(nèi)存區(qū)域存放了對象實例及數(shù)組(所有new的對象)。
其大小通過-Xms
(最小值)和-Xmx
(最大值)參數(shù)設(shè)置,-Xms為JVM啟動時申請的最小內(nèi)存,默認為操作系統(tǒng)物理內(nèi)存的1/64但小于1G,-Xmx
為JVM可申請的最大內(nèi)存,默認為物理內(nèi)存的1/4但小于1G,默認當(dāng)空余堆內(nèi)存小于40%時,JVM會增大Heap到-Xmx
指定的大小,可通過-XX:MinHeapFreeRation=
來指定這個比列;當(dāng)空余堆內(nèi)存大于70%時,JVM會減小heap的大小到-Xms指定的大小,可通過XX:MaxHeapFreeRation=
來指定這個比列,對于運行系統(tǒng),為避免在運行時頻繁調(diào)整Heap的大小,通常-Xms與-Xmx的值設(shè)成一樣。
由于現(xiàn)在收集器都是采用分代收集算法,堆被劃分為新生代和老年代。新生代主要存儲新創(chuàng)建的對象和尚未進入老年代的對象。老年代存儲經(jīng)過多次新生代GC(Minor GC)任然存活的對象。
新生代: 程序新創(chuàng)建的對象都是從新生代分配內(nèi)存,新生代由
Eden Space
和兩塊相同大小的Survivor Space
(通常又稱S0和S1或From和To)構(gòu)成,可通過-Xmn參數(shù)來指定新生代的大小,也可以通過-XX:SurvivorRation
來調(diào)整Eden Space
及Survivor Space
的大小。老年代: 用于存放經(jīng)過多次新生代GC任然存活的對象,例如緩存對象,新建的對象也有可能直接進入老年代,主要有兩種情況:
1、大對象,可通過啟動參數(shù)設(shè)置
-XX:PretenureSizeThreshold=1024
(單位為字節(jié),默認為0)來代表超過多大時就不在新生代分配,而是直接在老年代分配。2、大的數(shù)組對象,切數(shù)組中無引用外部對象。 老年代所占的內(nèi)存大小為-Xmx對應(yīng)的值減去-Xmn對應(yīng)的值。
Young Generation 即圖中的Eden + From Space + To Space Eden 存放新生的對象 Survivor Space 有兩個,存放每次垃圾回收后存活的對象 Old Generation Tenured Generation 即圖中的Old Space 主要存放應(yīng)用程序中生命周期長的存活對象
5.程序計數(shù)器
是最小的一塊內(nèi)存區(qū)域,它的作用是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器,在虛擬機的模型里,字節(jié)碼解釋器工作時就是通過改變這個計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令,分支、循環(huán)、異常處理、線程恢復(fù)等基礎(chǔ)功能都需要依賴計數(shù)器完成。
直接內(nèi)存并不是虛擬機內(nèi)存的一部分,也不是Java虛擬機規(guī)范中定義的內(nèi)存區(qū)域。jdk1.4中新加入的NIO,引入了通道與緩沖區(qū)的IO方式,它可以調(diào)用Native方法直接分配堆外內(nèi)存,這個堆外內(nèi)存就是本機內(nèi)存,不會影響到堆內(nèi)存的大小。
Java堆內(nèi)存是操作系統(tǒng)分配給JVM的內(nèi)存的一部分。
當(dāng)我們創(chuàng)建對象時,它們存儲在Java堆內(nèi)存中.
為了便于垃圾回收,Java堆空間分成三個區(qū)域,分別叫作New Generation, Old Generation或叫作Tenured Generation,還有Perm Space。
你可以通過用JVM的命令行選項 -Xms, -Xmx, -Xmn來調(diào)整Java堆空間的大小。不要忘了在大小后面加上”M”或者”G”來表示單位。舉個例子,你可以用 -Xmx256m來設(shè)置堆內(nèi)存最大的大小為256MB。
你可以用JConsole或者 Runtime.maxMemory(), Runtime.totalMemory(), Runtime.freeMemory()來查看Java中堆內(nèi)存的大小。
你可以使用命令“jmap”來獲得heap dump,用“jhat”來分析heap dump。
Java堆空間不同于棧空間,棧空間是用來儲存調(diào)用棧和局部變量的。
Java垃圾回收器是用來將死掉的對象(不再使用的對象)所占用的內(nèi)存回收回來,再釋放到Java堆空間中。
當(dāng)你遇到j(luò)ava.lang.outOfMemoryError時,不要緊張,有時候僅僅增加堆空間就可以了,但如果經(jīng)常出現(xiàn)的話,就要看看Java程序中是不是存在內(nèi)存泄露了。
- 請使用Profiler和Heap dump分析工具來查看Java堆空間,可以查看給每個對象分配了多少內(nèi)存。
看完上述內(nèi)容,你們對JVM的結(jié)構(gòu)和運行機制有進一步的了解嗎?如果還想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀。