小編給大家分享一下JVM的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
成都創(chuàng)新互聯(lián)擁有網(wǎng)站維護(hù)技術(shù)和項目管理團(tuán)隊,建立的售前、實施和售后服務(wù)體系,為客戶提供定制化的做網(wǎng)站、網(wǎng)站制作、網(wǎng)站維護(hù)、內(nèi)江機(jī)房主機(jī)托管解決方案。為客戶網(wǎng)站安全和日常運維提供整體管家式外包優(yōu)質(zhì)服務(wù)。我們的網(wǎng)站維護(hù)服務(wù)覆蓋集團(tuán)企業(yè)、上市公司、外企網(wǎng)站、商城網(wǎng)站開發(fā)、政府網(wǎng)站等各類型客戶群體,為全球近1000家企業(yè)提供全方位網(wǎng)站維護(hù)、服務(wù)器維護(hù)解決方案。
追本溯源——堆和棧
堆通常是一個可以被看做一棵樹的數(shù)組對象,棧是一種只能在一端進(jìn)行插入和刪除操作的先進(jìn)后出線性表,JVM的本質(zhì)是堆和棧
第一,從軟件設(shè)計的角度看,棧代表了處理邏輯,而堆代表了數(shù)據(jù)。這樣分開,使得處理邏輯更為清晰。分而治之的思想。這種隔離、模塊化的思想在軟件設(shè)計的方方面面都有體現(xiàn)。
第二,堆與棧的分離,使得堆中的內(nèi)容可以被多個棧共享(也可以理解為多個線程訪問同一個對象)。這種共享的收益是很多的。一方面這種共享提供了一種有效的數(shù)據(jù)交互方式(如:共享內(nèi)存),另一方面,堆中的共享常量和緩存可以被所有棧訪問,節(jié)省了空間。
第三,棧因為運行時的需要,比如保存系統(tǒng)運行的上下文,需要進(jìn)行地址段的劃分。由于棧只能向上增長,因此就會限制住棧存儲內(nèi)容的能力。而堆不同,堆中的對象是可以根據(jù)需要動態(tài)增長的,因此棧和堆的拆分,使得動態(tài)增長成為可能,相應(yīng)棧中只需記錄堆中的一個地址即可。
第四,面向?qū)ο缶褪嵌押蜅5耐昝澜Y(jié)合。其實,面向?qū)ο蠓绞降某绦蚺c以前結(jié)構(gòu)化的程序在執(zhí)行上沒有任何區(qū)別。但是,面向?qū)ο蟮囊?,使得對待問題的思考方式發(fā)生了改變,而更接近于自然方式的思考。當(dāng)我們把對象拆開,你會發(fā)現(xiàn),對象的屬性其實就是數(shù)據(jù),存放在堆中;而對象的行為(方法),就是運行邏輯,放在棧中。我們在編寫對象的時候,其實即編寫了數(shù)據(jù)結(jié)構(gòu),也編寫的處理數(shù)據(jù)的邏輯。不得不承認(rèn),面向?qū)ο蟮脑O(shè)計,確實很美。
JVM運行機(jī)制
此圖看出jvm內(nèi)存結(jié)構(gòu)
JVM內(nèi)存結(jié)構(gòu)主要包括兩個子系統(tǒng)和兩個組件。兩個子系統(tǒng)分別是Classloader子系統(tǒng)和Executionengine(執(zhí)行引擎)子系統(tǒng);兩個組件分別是Runtimedataarea(運行時數(shù)據(jù)區(qū)域)組件和Nativeinterface(本地接口)組件。
Classloader子系統(tǒng)的作用:根據(jù)給定的全限定名類名(如java.lang.Object)來裝載class文件的內(nèi)容到Runtimedataarea中的methodarea(方法區(qū)域)。Java程序員可以extendsjava.lang.ClassLoader類來寫自己的Classloader。
Executionengine子系統(tǒng)的作用:執(zhí)行classes中的指令。任何JVMspecification實現(xiàn)(JDK)的核心都是Executionengine,不同的JDK例如Sun的JDK和IBM的JDK好壞主要就取決于他們各自實現(xiàn)的Executionengine的好壞。
Nativeinterface組件:與nativelibraries交互,是其它編程語言交互的接口。當(dāng)調(diào)用native方法的時候,就進(jìn)入了一個全新的并且不再受虛擬機(jī)限制的世界,所以也很容易出現(xiàn)JVM無法控制的nativeheapOutOfMemory。
RuntimeDataArea組件:這就是我們常說的JVM的內(nèi)存了
JVM的生命周期
一、首先分析兩個概念
JVM實例和JVM執(zhí)行引擎實例
(1)JVM實例對應(yīng)了一個獨立運行的java程序,它是進(jìn)程級別。
(2)JVM執(zhí)行引擎實例則對應(yīng)了屬于用戶運行程序的線程,它是線程級別的。
二、JVM的生命周期
(1)JVM實例的誕生:當(dāng)啟動一個Java程序時,一個JVM實例就產(chǎn)生了,任何一個擁有public static void main(String[] args)函數(shù)的class都可以作為JVM實例運行的起點。
(2)JVM實例的運行 main()作為該程序初始線程的起點,任何其他線程均由該線程啟動。JVM內(nèi)部有兩種線程:守護(hù)線程和非守護(hù)線程,main()屬于非守護(hù)線程,守護(hù)線程通常由JVM自己使用,java程序也可以標(biāo)明自己創(chuàng)建的線程是守護(hù)線程。
(3)JVM實例的消亡:當(dāng)程序中的所有非守護(hù)線程都終止時,JVM才退出;若安全管理器允許,程序也可以使用Runtime類或者System.exit()來退出。
類的生命
一個java類的完整的生命周期會經(jīng)歷加載、連接、初始化、使用、和卸載五個階段,當(dāng)然也有在加載或者連接之后沒有被初始化就直接被使用的情況
雙親委派模型是一種組織類加載器之間關(guān)系的一種規(guī)范,他的工作原理是:如果一個類加載器收到了類加載的請求,它不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,這樣層層遞進(jìn),最終所有的加載請求都被傳到最頂層的啟動類加載器中,只有當(dāng)父類加載器無法完成這個加載請求(它的搜索范圍內(nèi)沒有找到所需的類)時,才會交給子類加載器去嘗試加載.
認(rèn)識JVM內(nèi)存模型
對于JVM內(nèi)存,程序員只需要關(guān)注
對象去哪兒——堆內(nèi)存(包括新生代和老年代,新生代又分為Enden區(qū)和兩個Survivor區(qū)),堆內(nèi)存用于存放對象,合理分區(qū)主要是為了提高垃圾回收效率,新創(chuàng)建的對象會在Enden區(qū),經(jīng)歷Minor GC后會到Survivor區(qū),經(jīng)歷一般15次GC還存活的話會進(jìn)入老年代。
函數(shù)如何調(diào)用——棧內(nèi)存用于運行線程,它們包含了方法里的臨時數(shù)據(jù)、堆里其它對象引用的特定數(shù)據(jù)。
類去哪兒——方法區(qū)用來存儲類型信息(運行時常量和靜態(tài)變量)和方法代碼和構(gòu)造函數(shù)代碼,通常也叫永久代,JDK8用元空間代替永久代
JVM資源一般分為兩種CPU和內(nèi)存,CPU代表著線程棧,內(nèi)存代表著堆,而往往生產(chǎn)環(huán)境JVM問題一般都是這兩種資源不足導(dǎo)致的,當(dāng)線程棧使用不當(dāng)?shù)臅r候,通常會CPU爆滿,當(dāng)堆內(nèi)存使用不當(dāng)?shù)臅r候,通常會出現(xiàn)內(nèi)存溢出。
內(nèi)存管理清潔工——垃圾回收
Java程序語言中的一個最大優(yōu)點是自動垃圾回收,Java垃圾回收會找出沒用的對象,把它從內(nèi)存中移除并釋放出內(nèi)存給以后創(chuàng)建的對象使用。下面圖片生動對比手動垃圾回收和自動垃圾回收的區(qū)別。垃圾回收重點關(guān)注碎片和性能。
初識垃圾回收算法
按回收策略
(1).引用計數(shù)算法:
給對象中添加一個引用計數(shù)器,每當(dāng)有一個地方引用它時,計數(shù)器值就加1;當(dāng)引用失效時,計數(shù)器值就減1;任何時刻計數(shù)器都為0的對象就是不再被使用的,垃圾收集器將回收該對象使用的內(nèi)存。引用計數(shù)算法實現(xiàn)簡單,效率很高,微軟的COM技術(shù)、ActionScript、Python等都使用了引用計數(shù)算法進(jìn)行內(nèi)存管理,但是引用計數(shù)算法對于對象之間相互循環(huán)引用問題難以解決,因此java并沒有使用引用計數(shù)算法。
(2).根搜索算法:
通過一系列的名為“GC Root”的對象作為起點,從這些節(jié)點向下搜索,搜索所走過的路徑稱為引用鏈(Reference Chain),當(dāng)一個對象到GC Root沒有任何引用鏈相連時,則該對象不可達(dá),該對象是不可使用的,垃圾收集器將回收其所占的內(nèi)存。
在Java語言里,可作為GC Roots對象的包括如下幾種:
a.System Class,像rt.jar里面的java.util.*
b.Thread,開始狀態(tài)的線程
c.虛擬機(jī)棧(棧楨中的本地變量表)中的引用的對象
d.方法區(qū)中的類靜態(tài)屬性引用的對象
e.方法區(qū)中的常量引用的對象
f.本地方法棧中JNI的引用的對象
(3).標(biāo)記-清除算法:
最基礎(chǔ)的垃圾收集算法,算法分為“標(biāo)記”和“清除”兩個階段:首先標(biāo)記出所有需要回收的對象,在標(biāo)記完成之后統(tǒng)一回收掉所有被標(biāo)記的對象。
標(biāo)記-清除算法的缺點有兩個:首先,效率問題,標(biāo)記和清除效率都不高。其次,標(biāo)記清除之后會產(chǎn)生大量的不連續(xù)的內(nèi)存碎片,空間碎片太多會導(dǎo)致當(dāng)程序需要為較大對象分配內(nèi)存時無法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集動作。
(4).復(fù)制算法:
將可用內(nèi)存按容量分成大小相等的兩塊,每次只使用其中一塊,當(dāng)這塊內(nèi)存使用完了,就將還存活的對象復(fù)制到另一塊內(nèi)存上去,然后把使用過的內(nèi)存空間一次清理掉。這樣使得每次都是對其中一塊內(nèi)存進(jìn)行回收,內(nèi)存分配時不用考慮內(nèi)存碎片等復(fù)雜情況,只需要移動堆頂指針,按順序分配內(nèi)存即可,實現(xiàn)簡單,運行高效。
復(fù)制算法的缺點顯而易見,可使用的內(nèi)存降為原來一半。
(5).標(biāo)記-清除-整理算法:
標(biāo)記-整理算法在標(biāo)記-清除算法基礎(chǔ)上做了改進(jìn),標(biāo)記階段是相同的標(biāo)記出所有需要回收的對象,在標(biāo)記完成之后不是直接對可回收對象進(jìn)行清理,而是讓所有存活的對象都向一端移動,在移動過程中清理掉可回收的對象,這個過程叫做整理。
標(biāo)記-整理算法相比標(biāo)記-清除算法的優(yōu)點是內(nèi)存被整理以后不會產(chǎn)生大量不連續(xù)內(nèi)存碎片問題。
復(fù)制算法在對象存活率高的情況下就要執(zhí)行較多的復(fù)制操作,效率將會變低,而在對象存活率高的情況下使用標(biāo)記-整理算法效率會大大提高。
按分區(qū)回收
(1).分代算法:
根據(jù)對象的存活周期的不同將內(nèi)存劃分為幾塊。一般把java堆分為新生代和老年代,這樣就可以根據(jù)各個年代的特點采用最適當(dāng)?shù)氖占惴?。在新生代,每次垃圾收集時都發(fā)現(xiàn)有大批對象死去,只有少量存活,那就選用復(fù)制算法,只需要付出少量存活對象的復(fù)制成本就可以完成收集。而老年代中因為對象存活率高、沒有額外空間對他進(jìn)行分配擔(dān)保,就必須使用“標(biāo)記-整理”算法進(jìn)行回收。
按系統(tǒng)線程
串行/并行回收方式:在GC過程中,單線程/多線程收集器采用Stop-the-World機(jī)制,做事專一吞吐量高;
并發(fā)回收:工作線程和垃圾回收線程并發(fā)執(zhí)行,一心二用,吞吐量較低,不過保證在GC的時候,其它用戶線程可以工作;
垃圾收集器
JVM常見參數(shù)
最后匯總一下JVM常見配置
類加載設(shè)置
-XX:+TraceClassLoading:類加載日志
-XX:+TraceClassUnloading:類卸載日志
堆設(shè)置
-Xms:初始堆大小
-Xmx:最大堆大小
-XX:NewSize=n:設(shè)置年輕代大小
-XX:NewRatio=n:設(shè)置年輕代和年老代的比值。如:為3,表示年輕代與年老代比值為1:3,年輕代占整個年輕代年老代和的1/4
-XX:SurvivorRatio=n:年輕代中Eden區(qū)與兩個Survivor區(qū)的比值。注意Survivor區(qū)有兩個。如:3,表示Eden:Survivor=3:2,一個Survivor區(qū)占整個年輕代的1/5
-XX:MaxPermSize=n:設(shè)置持久代大小
收集器設(shè)置
-XX:+UseSerialGC:設(shè)置串行收集器
-XX:+UseParallelGC:設(shè)置并行收集器
-XX:+UseParalledlOldGC:設(shè)置并行年老代收集
-XX:+UseConcMarkSweepGC:設(shè)置并發(fā)收集器
垃圾回收統(tǒng)計信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
并行收集器設(shè)置
-XX:ParallelGCThreads=n:設(shè)置并行收集器收集時使用的CPU數(shù)。并行收集線程數(shù)。
-XX:MaxGCPauseMillis=n:設(shè)置并行收集最大暫停時間
-XX:GCTimeRatio=n:設(shè)置垃圾回收時間占程序運行時間的百分比。公式為1/(1+n)
并發(fā)收集器設(shè)置
-XX:+CMSIncrementalMode:設(shè)置為增量模式。適用于單CPU情況
-XX:ParallelGCThreads=n:設(shè)置并發(fā)收集器年輕代收集方式為并行收集時,使用的CPU數(shù)。并行收集線程數(shù)。
以上是“JVM的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
網(wǎng)頁標(biāo)題:JVM的示例分析
當(dāng)前URL:http://jinyejixie.com/article0/gpijio.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動態(tài)網(wǎng)站、外貿(mào)網(wǎng)站建設(shè)、營銷型網(wǎng)站建設(shè)、搜索引擎優(yōu)化、外貿(mào)建站、域名注冊
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)