JVM 解讀 - 學習筆記

Java生態(tài)

Java 生態(tài)

1. Java 源碼編譯

語法糖(Syntactic sugar):這種語法對語言的功能并沒有影響榄笙,但是更方便程序員使用柳刮。通常來說使用語法糖能夠增加程序的可讀性,從而減少程序代碼出錯的機會. E.g.?用a[i]表示*(a+i),用a[i][j]表示*(*(a+i)+j),?從面向過程到面向?qū)ο笠彩且环N語法糖

2. 解析執(zhí)行



Java編譯器:將Java源文件(.java文件)編譯成字節(jié)碼文件(.class文件咳秉,是特殊的二進制文件婉支,二進制字節(jié)碼文件),這種字節(jié)碼就是JVM的“機器語言”澜建。javac.exe可以簡單看成是Java編譯器向挖。

Java解釋器:是JVM的一部分。Java解釋器用來解釋執(zhí)行Java編譯器編譯后的程序霎奢。java.exe可以簡單看成是Java解釋器户誓。

JVM:一種能夠運行Java字節(jié)碼(Java?bytecode)的虛擬機。

JDK=JRE + javac compiler+monitor tool.? ?tomcat need jdk in unix for compile.

Tomcat can be run as a daemon using the jsvc tool from the commons-daemon project. Source tarballs for jsvc are included with the Tomcat binaries, and need to be compiled. Building jsvc requires a C ANSI compiler (such as GCC), GNU Autoconf, and a JDK.

字節(jié)碼:字節(jié)碼是已經(jīng)經(jīng)過編譯幕侠,但與特定機器碼無關(guān)帝美,需要解釋器轉(zhuǎn)譯后才能成為機器碼的中間代碼。

Java字節(jié)碼:是Java虛擬機執(zhí)行的一種指令格式晤硕。

解釋器:是一種電腦程序悼潭,能夠把高級編程語言一行一行直接翻譯運行。解釋器不會一次把整個程序翻譯出來舞箍,只像一位“中間人”舰褪,每次運行程序時都要先轉(zhuǎn)成另一種語言再作運行,因此解釋器的程序運行速度比較緩慢疏橄。它每翻譯一行程序敘述就立刻運行占拍,然后再翻譯下一行,再運行捎迫,如此不停地進行下去晃酒。它會先將源碼翻譯成另一種語言,以供多次運行而無需再經(jīng)編譯窄绒。其制成品無需依賴編譯器而運行贝次,程序運行速度比較快。

即時編譯(Just-in-time compilation: JIT):又叫實時編譯彰导、及時編譯蛔翅。是指一種在運行時期把字節(jié)碼編譯成原生機器碼的技術(shù)敲茄,一句一句翻譯源代碼,但是會將翻譯過的代碼緩存起來以降低性能耗損山析。這項技術(shù)是被用來改善虛擬機的性能的堰燎。

JIT編譯器是JRE的一部分。原本的Java程序都是要經(jīng)過解釋執(zhí)行的盖腿,其執(zhí)行速度肯定比可執(zhí)行的二進制字節(jié)碼程序慢爽待。為了提高執(zhí)行速度,引入了JIT翩腐。在運行時鸟款,JIT會把翻譯過來的機器碼保存起來,以備下次使用茂卦。而如果JIT對每條字節(jié)碼都進行編譯何什,則會負擔過重,所以等龙,JIT只會對經(jīng)常執(zhí)行的字節(jié)碼進行編譯处渣,如循環(huán),高頻度使用的方法等蛛砰。它會以整個方法為單位罐栈,一次性將整個方法的字節(jié)碼編譯為本地機器碼,然后直接運行編譯后的機器碼泥畅。

1.1.1類的加載時機

Java類的加載是動態(tài)的荠诬,它并不會一次性將所有類全部加載后再運行,而是保證程序運行的基礎類(像是基類)完全加載到jvm中位仁,至于其他類柑贞,則在需要的時候才加載。這當然就是為了節(jié)省內(nèi)存開銷聂抢。

虛擬機規(guī)范則是嚴格規(guī)定了有且只有5種情況必須立即對類進行“初始化”(class文件加載到JVM中):

????a. 創(chuàng)建類的實例(new 的方式)钧嘶。訪問某個類或接口的靜態(tài)變量,或者對該靜態(tài)變量賦值琳疏,調(diào)用類的靜態(tài)方法

????b. 反射

????c. 初始化某個類的子類有决,則其父類也會被初始化

????d. Java虛擬機啟動時被標明為啟動類的類,直接使用java.exe命令來運行某個主類(包含main方法的那個類)

????e. 當使用JDK1.7的動態(tài)語言支持時

1.1.2如何將類加載到jvm

class文件是通過類的加載器裝載到jvm中的類加載器(ClassLoader)是Java語言的一項創(chuàng)新空盼,也是Java流行的一個重要原因

加載類的開放性

在類加載的第一階段“加載”過程中疮薇,需要通過一個類的全限定名來獲取定義此類的二進制字節(jié)流,完成這個動作的代碼塊就是類加載器我注。這一動作是放在Java虛擬機外部去實現(xiàn)的,以便讓應用程序自己決定如何獲取所需的類迟隅。

虛擬機規(guī)范并沒有指明二進制字節(jié)流要從一個Class文件獲取但骨,或者說根本沒有指明從哪里獲取励七、怎樣獲取。這種開放使得Java在很多領(lǐng)域得到充分運用奔缠,例如:

????????從ZIP包中讀取掠抬,這很常見,成為JAR校哎,EAR两波,WAR格式的基礎

????????從網(wǎng)絡中獲取,最典型的應用就是Applet

????????運行時計算生成闷哆,最典型的是動態(tài)代理技術(shù)腰奋,在java.lang.reflect.Proxy中,就是用了ProxyGenerator.generateProxyClass來為特定接口生成形式為“*$Proxy”的代理類的二進制字節(jié)流

? ? ? ? 由其他文件生成抱怔,最典型的JSP應用劣坊,由JSP文件生成對應的Class類

從java虛擬機角度來講,只存在兩種不同的類加載器:

? ? ? ?(1)一種是啟動類加載器屈留,由C++語言實現(xiàn)的局冰,屬于虛擬機的一部分;

? ? ? ?(2)一種是所有的其他類加載器灌危,這些都是由Java實現(xiàn)的康二,獨立于虛擬機外部,繼承自java.lang.ClassLoader勇蝙;

從開發(fā)人員角度來講沫勿,?Java默認有三種類加載器

各個加載器的工作責任:

1)Bootstrap ClassLoader:負責加載$JAVA_HOME中jre/lib/rt.jar里所有的class,這個加載器很特殊浅蚪,它不是Java類藕帜,因此它不需要被別人加載,它嵌套在Java虛擬機內(nèi)核里面惜傲,也就是JVM啟動的時候Bootstrap就已經(jīng)啟動洽故,它是用C++寫的二進制代碼(不是字節(jié)碼,它可以去加載別的類盗誊,不是ClassLoader子類

2)Extension ClassLoader:負責加載java平臺中擴展功能的一些jar包时甚,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目錄下的jar包

3)App ClassLoader:負責記載classpath中指定的jar包及目錄中class

工作過程:

1、當AppClassLoader加載一個class時哈踱,它首先不會自己去嘗試加載這個類荒适,而是把類加載請求委派給父類加載器ExtClassLoader去完成。

2开镣、當ExtClassLoader加載一個class時刀诬,它首先也不會自己去嘗試加載這個類,而是把類加載請求委派給BootStrapClassLoader去完成邪财。

3陕壹、如果BootStrapClassLoader加載失斨视(例如在$JAVA_HOME/jre/lib里未查找到該class),會使用ExtClassLoader來嘗試加載糠馆;

4嘶伟、若ExtClassLoader也加載失敗,則會使用AppClassLoader來加載

5又碌、如果AppClassLoader也加載失敗九昧,則會報出異常ClassNotFoundException

其實這就是所謂的雙親委派模型 (parent delegation model)。簡單來說:如果一個類加載器收到了類加載的請求毕匀,它首先不會自己去嘗試加載這個類铸鹰,而是把請求委托給父加載器去完成,依次向上期揪。(https://juejin.im/post/5b3cc84ee51d4519873f08da)

好處:防止內(nèi)存中出現(xiàn)多份同樣的字節(jié)碼(安全性角度)

????特別說明:

類加載器在成功加載某個類之后掉奄,會把得到的?java.lang.Class類的實例緩存起來。下次再請求加載該類的時候凤薛,類加載器會直接使用緩存的類的實例姓建,而不會嘗試再次加載

雙親委派模型在JDK1.2中引入缤苫,但不是強制性的速兔。在一定條件下,為了完成某些操作活玲,可以“破壞”模型涣狗。

? ? 1.重新loadClass方法

? ? 2.利用線程上下文加載器(Thread Context ClassLoader)。這個類加載器可以通過java.lang.Thread類的 setContextClassLoaser()方法進行設置舒憾,如果創(chuàng)建線程時還未設置镀钓,它將會從父線程中繼承 一個,如果在應用程序的全局范圍內(nèi)都沒有設置過的話镀迂,那這個類加載器默認就是應用程序 類加載器丁溅。

????????例如JNDI服務,但是當JNDI要對資源進行集中化管理時探遵,他需要調(diào)用其他公司實現(xiàn)并部署在應用程序的classpath下的JNDI接口窟赏,因為這些代碼是需要我們開發(fā)者自己來實現(xiàn)的,這時啟動類加載器是無法識別這些類的箱季,于是乎出現(xiàn)了一種線程上下文加載器(Thread Context ClassLoader)解幽,JNDI服務可以調(diào)用該加載器去加載所需要的代碼唬渗,就是通過父類加載器去請求子類加載器來實現(xiàn)的

? ? 3.為了實現(xiàn)熱插拔,熱部署核无,模塊化辖所,意思是添加一個功能或減去一個功能不用重啟,只需要把這模塊連同類加載器一起換掉就實現(xiàn)了代碼的熱替換。

那能不能自己寫個類叫java.lang.System?

答案:通常不可以最疆,但可以采取另類方法達到這個需求。

解釋:為了不讓我們寫System類蚤告,類加載采用委托機制,這樣可以保證爸爸們優(yōu)先服爷,爸爸們能找到的類杜恰,兒子就沒有機會加載。而System類是Bootstrap加載器加載的仍源,就算自己重寫心褐,也總是使用Java系統(tǒng)提供的System,自己寫的System類根本沒有機會得到加載笼踩。

但是逗爹,我們可以自己定義一個類加載器來達到這個目的,為了避免雙親委托機制嚎于,這個類加載器也必須是特殊的掘而。由于系統(tǒng)自帶的三個類加載器都加載特定目錄下的類,如果我們自己的類加載器放在一個特殊的目錄于购,那么系統(tǒng)的加載器就無法加載袍睡,也就是最終還是由我們自己的加載器加載。

https://www.ibm.com/developerworks/cn/java/j-lo-classloader/

https://www.zhihu.com/question/46719811

1.1.3類加載詳細過程

加載器加載到jvm中肋僧,接下來分為幾個步驟

1) 加載斑胜,查找并加載類的二進制數(shù)據(jù),在Java堆中也創(chuàng)建一個java.lang.Class類的對象嫌吠。

2) 連接止潘,連接又包含三塊內(nèi)容:驗證、準備辫诅、初始化凭戴。? 1)驗證,文件格式泥栖、元數(shù)據(jù)簇宽、字節(jié)碼、符號引用驗證吧享;? 2)準備魏割,為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默認值钢颂; 3)解析钞它,把類中的符號引用轉(zhuǎn)換為直接引用

3) 初始化,為類的靜態(tài)變量賦予正確的初始值。

https://juejin.im/post/5b3cc84ee51d4519873f08da

https://www.mrsssswan.club/2018/06/30/jvm-start1/


1.1.4 JIT即時編譯器 (Just-in-time compiler)

Just in time編譯遭垛,也叫做運行時編譯尼桶,不同于 C / C++ 語言直接被翻譯成機器指令,javac把java的源文件翻譯成了class文件锯仪,而class文件中全都是Java字節(jié)碼泵督。那么,JVM在加載了這些class文件以后庶喜,針對這些字節(jié)碼小腊,逐條取出,逐條執(zhí)行久窟,這種方法就是解釋執(zhí)行(interprete)秩冈。

還有一種,就是compile, 把這些Java字節(jié)碼重新編譯優(yōu)化斥扛,生成機器碼入问,讓CPU直接執(zhí)行。這樣編出來的代碼效率會更高稀颁。通常芬失,我們不必把所有的Java方法都編譯成機器碼,只需要把調(diào)用最頻繁峻村,占據(jù)CPU時間最長的方法找出來將其編譯成機器碼麸折。這種調(diào)用最頻繁的Java方法就是我們常說的熱點方法

因為編譯也是要花費時間的,我們一般對熱點代碼做compile粘昨,非熱點代碼直接interprete就好了垢啼。

熱點代碼解釋:一、多次調(diào)用的方法张肾。二芭析、多次執(zhí)行的循環(huán)體

使用熱點探測來檢測是否為熱點代碼,熱點探測有兩種方式:采樣, 與計數(shù)器

目前HotSpot使用的是計數(shù)器的方式吞瞪,它為每個方法準備了兩類計數(shù)器:

? ? ? ? 1) 方法調(diào)用計數(shù)器(Invocation Counter)

? ? ? ? 2) 回邊計數(shù)器(Back EdgeCounter)馁启。

在確定虛擬機運行參數(shù)的前提下,這兩個計數(shù)器都有一個確定的閾值芍秆,當計數(shù)器超過閾值溢出了惯疙,就會觸發(fā)JIT編譯

https://www.ibm.com/developerworks/cn/java/j-lo-just-in-time/

https://zhuanlan.zhihu.com/p/28476709

1.2 JVM的內(nèi)存模型


方法區(qū):?線程共享妖啥,用于儲存已被虛擬機加載的類信息霉颠、常量、靜態(tài)變量荆虱,即編譯器編譯后的代碼.?JDK 8的HotSpot JVM現(xiàn)在使用的是本地內(nèi)存來表示類的元數(shù)據(jù)蒿偎,這個區(qū)域就叫做元空間(meta space).?元空間的特點:充分利用了Java語言規(guī)范中的好處:類及相關(guān)的元數(shù)據(jù)的生命周期與類加載器的一致; 每個加載器有專門的存儲空間;? 只進行線性分配.不會單獨回收某個類; 省掉了GC掃描及壓縮的時間. 元空間里的對象的位置是固定的, 提高Full GC的性能朽们,在Full GC期間,Metadata到Metadata pointers之間不需要掃描了诉位,別小看這幾納秒時間

?http://www.reibang.com/p/7b88aa16c2f6

堆:?是JVM中最大的一塊區(qū)域骑脱,線程共享,此區(qū)唯一的目的就是存放對象實例 (方法區(qū)中的類實例化之后)苍糠,幾乎所有對象實例都在這里分配叁丧,但是隨著JIT編譯器及逃逸分析技術(shù)的發(fā)展,棧上分配岳瞭、標量替換優(yōu)化技術(shù)將會導致一些微妙的變化歹袁,所有對象都分配在堆上也漸漸變的不是那么絕對.

針對于jdk1.7之后:常量池位于堆中. 常量池存儲的是:

? ? ? ?a)? ?字面量(Literal):文本字符串等---->用雙引號引起來的字符串字面量都會進這里面

? ? ? ?b)? ?符號引用(Symbolic References) - 類和接口的全限定名(Full Qualified Name) - 字段的名稱和描述符(Descriptor) - 方法的名稱和描述符

字符串常量池只存儲引用,不存儲內(nèi)容

虛擬機棧/棧內(nèi)存

?見題目for string.intern()? https://zhuanlan.zhihu.com/p/39536807

虛擬機棧:即我們平時經(jīng)常說的棧內(nèi)存寝优,也是線程私有,是Java方法執(zhí)行時的內(nèi)存模型枫耳,類中的每個方法執(zhí)行時都會創(chuàng)建一個棧幀(frame)用于儲存以下內(nèi)容:

? ??棧幀(frame):

? ?局部變量表:32位變量槽乏矾,存放了編譯期可知的各種基本數(shù)據(jù)類型的值、對象引用迁杨、returnAddress類型钻心。Stack memory only contains?local primitive variables?and?reference?variables?to objects in heap?space.

? ??操作數(shù)棧:基于棧的執(zhí)行引擎,虛擬機把操作數(shù)棧作為它的工作區(qū)铅协,大多數(shù)指令都要從這里彈出數(shù)據(jù)捷沸、執(zhí)行運算,然后把結(jié)果壓回操作數(shù)棧狐史。

????動態(tài)連接:每個棧幀都包含一個指向運行時常量池(方法區(qū)的一部分)中該棧幀所屬方法的引用痒给。持有這個引用是為了支持方法調(diào)用過程中的動態(tài)連接。Class文件的常量池中有大量的符號引用骏全,字節(jié)碼中的方法調(diào)用指令就以常量池中指向方法的符號引用為參數(shù)苍柏。這些符號引用一部分會在類加載階段或第一次使用的時候轉(zhuǎn)化為直接引用,這種轉(zhuǎn)化稱為靜態(tài)解析姜贡。另一部分將在每一次的運行期間轉(zhuǎn)化為直接應用试吁,這部分稱為動態(tài)連接。

????方法出口:返回方法被調(diào)用的位置楼咳,恢復上層方法的局部變量和操作數(shù)棧熄捍,如果無返回值,則把它壓入調(diào)用者的操作數(shù)棧母怜。

frameis used to store data and partial results, as well as to perform dynamic linking, return values for methods, and dispatch exceptions.

A new frame is created each time a method is invoked. A frame is destroyed when its method invocation completes

Each frame has its own array of local variables (§2.6.1), its own operand stack (§2.6.2), and a reference to the run-time constant pool (§2.5.5) of the class of the current method.

本地方法棧:線程私有余耽,與虛擬機棧類似,為native方法服務糙申。

程序計數(shù)器:一塊較小的內(nèi)存空間宾添,可以看作當前線程所執(zhí)行的字節(jié)碼行號指示器船惨。

????????程序計數(shù)器是線程私有,各線程之間互不影響

????????如果正在執(zhí)行java方法缕陕,計數(shù)器記錄的是正在執(zhí)行的虛擬機字節(jié)碼指令地址

????????如果執(zhí)行native方法粱锐,這個計數(shù)器為null

????????程序計數(shù)器也是在Java虛擬機規(guī)范中唯一沒有規(guī)定任何OutOfMemoryError異常情況的區(qū)域

舉例說明


宏觀簡述一下例子中的工作流程:

1、通過java.exe運行Java3yTest.class扛邑,隨后被加載到JVM中怜浅,元空間存儲著類的信息(包括類的名稱、方法信息蔬崩、字段信息..)恶座。

2、然后JVM找到Java3yTest的主函數(shù)入口(main)沥阳,為main函數(shù)創(chuàng)建棧幀跨琳,開始執(zhí)行main函數(shù)

3、main函數(shù)的第一條命令是Java3y java3y = new Java3y();就是讓JVM創(chuàng)建一個Java3y對象桐罕,但是這時候方法區(qū)中沒有Java3y類的信息脉让,所以JVM馬上加載Java3y類,把Java3y類的類型信息放到方法區(qū)中(元空間)

4功炮、加載完Java3y類之后溅潜,Java虛擬機做的第一件事情就是在堆區(qū)中為一個新的Java3y實例分配內(nèi)存, 然后調(diào)用構(gòu)造函數(shù)初始化Java3y實例,這個Java3y實例持有著指向方法區(qū)的Java3y類的類型信息(其中包含有方法表薪伏,java動態(tài)綁定的底層實現(xiàn))的引用

5滚澜、當使用java3y.setName("Java3y");的時候,JVM根據(jù)java3y引用找到Java3y對象嫁怀,然后根據(jù)Java3y對象持有的引用定位到方法區(qū)中Java3y類的類型信息的方法表设捐,獲得setName()函數(shù)的字節(jié)碼的地址

6、為setName()函數(shù)創(chuàng)建棧幀塘淑,開始運行setName()函數(shù)

從微觀上其實還做了很多東西挡育,正如上面所說的類加載過程(加載-->連接(驗證,準備朴爬,解析)-->初始化)即寒,在類加載完之后jvm為其分配內(nèi)存(分配內(nèi)存中也做了非常多的事)。由于這些步驟并不是一步一步往下走召噩,會有很多的“混沌bootstrap”的過程母赵,所以很難描述清楚。擴展閱讀(先有Class對象還是先有Object):?https://www.zhihu.com/question/30301819

https://www.journaldev.com/4098/java-heap-space-vs-stack-memory


1.7.1JVM垃圾回收

判斷對象死去有兩種方法:

? ? 1) 引用計數(shù)法-->這種難以解決對象之間的循環(huán)引用的問題

? ? 2) 可達性分析算法-->主流的JVM采用的是這種方式

回收對象的方法:?

????????標記-清除算法:(Mark-Sweep)算法具滴,如它的名字一樣凹嘲,算法分為“標記”和“清除”兩個階段:首先標記出所有需要回收的對象,在標記完成后統(tǒng)一回收掉所有被標記的對象构韵。

????????復制算法:?(Copying)的收集算法周蹭,它將可用內(nèi)存按容量劃分為大小相等的兩塊趋艘,每次只使用其中的一塊。當這一塊的內(nèi)存用完了凶朗,就將還存活著的對象復制到另外一塊上面瓷胧,然后再把已使用過的內(nèi)存空間一次清理掉

????????標記-壓縮算法:標記過程仍然與“標記-清除”算法一樣,但后續(xù)步驟不是直接對可回收對象進行清理棚愤,而是讓所有存活的對象都向一端移動搓萧,然后直接清理掉端邊界以外的內(nèi)存

????????分代收集算法 (一般GC常用方法。?其實就是組合上面的算法宛畦,不同的區(qū)域使用不同的算法)

無論是可達性分析算法瘸洛,還是垃圾回收算法,JVM使用的都是準確式GC(Type accurate GC.?給定某個位置上的某塊數(shù)據(jù), 知道其是不是指針次和。 與之相對的是保守與半保守式GC, 其實現(xiàn)較為簡單)反肋。JVM是使用一組稱為OopMap (object reference)的數(shù)據(jù)結(jié)構(gòu),來存儲所有的對象引用(這樣就不用遍歷整個內(nèi)存去查找了踏施,空間換時間)囚玫。 并且不會將所有的指令都生成OopMap,只會在安全點(SafePoint)上生成OopMap读规,在安全區(qū)域(Safe Region)上開始GC。

http://www.cnblogs.com/strinkbug/p/6376525.html

https://my.oschina.net/u/1757225/blog/1583822

在OopMap的協(xié)助下燃少,HotSpot可以快速且準確地完成GC Roots枚舉(可達性分析)束亏。上面所講的垃圾收集算法只能算是方法論,落地實現(xiàn)的是垃圾收集器:圖中兩個收集器之間有連線阵具,則說明它們可以配合使用.

Serial收集器碍遍,串行收集器是最古老,最穩(wěn)定以及效率高的收集器阳液,但可能會產(chǎn)生較長的停頓怕敬,只使用一個線程去回收。

ParNew收集器帘皿,ParNew收集器其實就是Serial收集器的多線程版本东跪。

Parallel收集器,Parallel Scavenge收集器類似ParNew收集器鹰溜,Parallel收集器更關(guān)注系統(tǒng)的吞吐量虽填。

Parallel Old收集器,Parallel Old是Parallel Scavenge收集器的老年代版本曹动,使用多線程“標記-整理”算法

CMS收集器斋日,CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器。它需要消耗額外的CPU和內(nèi)存資源墓陈,在CPU和內(nèi)存資源緊張恶守,CPU較少時第献,會加重系統(tǒng)負擔。CMS無法處理浮動垃圾兔港。CMS的“標記-清除”算法庸毫,會導致大量空間碎片的產(chǎn)生

G1收集器押框,G1 (Garbage-First)是一款面向服務器的垃圾收集器,主要針對配備多顆處理器及大容量內(nèi)存的機器.?以極高概率滿足GC停頓時間要求的同時,還具備高吞吐量性能特征岔绸。G1 is planned as the long term replacement for the Concurrent Mark-Sweep Collector (CMS). Comparing G1 with CMS, there are differences that make G1 a better solution. One difference is that G1 is a compacting collector.?Also, G1 offers more predictable garbage collection pauses than the CMS collector, and allows users to specify desired pause targets

? ??The older garbage collectors (serial, parallel, CMS) all structure the heap into three sections: young generation, old generation, and permanent generation of a fixed memory size.? ??

All memory objects end up in one of these three sections.

The G1 collector takes a different approach.

The heap is partitioned into a set of equal-sized heap regions, each a contiguous range of virtual memory. Certain region sets are assigned the same roles (eden, survivor, old) as in the older collectors, but there is not a fixed size for them. This provides greater flexibility in memory usage.


The heap is partitioned into a set of equal-sized heap regions, each a contiguous range of virtual memory. Certain region sets are assigned the same roles (eden, survivor, old) as in the older collectors, but there is not a fixed size for them. This provides greater flexibility in memory usage.


JVM 調(diào)試

32 JVM 優(yōu)于 64JVM

因為不需要考慮從一個虛擬機轉(zhuǎn)移到另一個虛機。所以sticky connection 不需考慮

DirectMemory

JVM除了堆內(nèi)存之外橡伞,就只有棧內(nèi)存和DirectMemory了盒揉。棧空間每個線程是固定的兑徘,線程數(shù)也沒可能多到可以占用這么多內(nèi)存的程序刚盈,所以懷疑的目標就在DirectMemory上了。

DirectMemory是java nio引入的挂脑,直接以native的方式分配內(nèi)存藕漱,不受jvm管理。這種方式是為了提高網(wǎng)絡和文件IO的效率崭闲,避免多余的內(nèi)存拷貝而出現(xiàn)的肋联。DirectMemory占用的大小沒有直接的工具或者API可以查看,不過這個在Bits類中是有兩個字段存儲了最大大小和已分配大小的刁俭,使用反射可以拿到這個數(shù)據(jù)橄仍。

Class<?>?c?=?Class.forName("java.nio.Bits");

Field?maxMemory?=?c.getDeclaredField("maxMemory");

maxMemory.setAccessible(true);

Field?reservedMemory?=?c.getDeclaredField("reservedMemory");

reservedMemory.setAccessible(true);

Long?maxMemoryValue?=?(Long)maxMemory.get(null);

Long?reservedMemoryValue?=?(Long)reservedMemory.get(null);

原來,DirectMemory 的默認大小是64M牍戚,而JDK6之前和JDK6的某些版本的SUN JVM侮繁,存在一個BUG,在用-Xmx設定堆空間大小的時候如孝,也設置了DirectMemory的大小宪哩。加入設置了-Xmx2048m,那么jvm最終可分配的內(nèi)存大小為4G多一些第晰,是預期的兩倍锁孟。

解決方式是設置jvm參數(shù)-XX:MaxDirectMemorySize=128m,指定DirectMemory的大小茁瘦。

getRuntime.exec()

占用資源很多罗岖,盡量避免使用。其調(diào)用時會先clone一個和現(xiàn)在虛擬機一樣環(huán)境變量的進程腹躁。用這個新進程去執(zhí)行外部命令

異步改消息隊列


參考資料

https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/G1GettingStarted/index.html

https://www.journaldev.com/2856/java-jvm-memory-model-memory-management-in-java#memory-management-in-java-8211-java-garbage-collection

http://www.reibang.com/p/63fe09fe1a60

https://www.baeldung.com/jvm-vs-jre-vs-jdk

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末桑包,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子纺非,更是在濱河造成了極大的恐慌哑了,老刑警劉巖赘方,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異弱左,居然都是意外死亡窄陡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進店門拆火,熙熙樓的掌柜王于貴愁眉苦臉地迎上來跳夭,“玉大人,你說我怎么就攤上這事们镜”姨荆” “怎么了?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵模狭,是天一觀的道長颈抚。 經(jīng)常有香客問我,道長嚼鹉,這世上最難降的妖魔是什么贩汉? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮锚赤,結(jié)果婚禮上匹舞,老公的妹妹穿的比我還像新娘。我一直安慰自己线脚,他們只是感情好赐稽,可當我...
    茶點故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著酒贬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪翠霍。 梳的紋絲不亂的頭發(fā)上锭吨,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天,我揣著相機與錄音寒匙,去河邊找鬼零如。 笑死,一個胖子當著我的面吹牛锄弱,可吹牛的內(nèi)容都是我干的考蕾。 我是一名探鬼主播,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼会宪,長吁一口氣:“原來是場噩夢啊……” “哼肖卧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起掸鹅,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤塞帐,失蹤者是張志新(化名)和其女友劉穎拦赠,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體葵姥,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡荷鼠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了榔幸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片允乐。...
    茶點故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖削咆,靈堂內(nèi)的尸體忽然破棺而出牍疏,到底是詐尸還是另有隱情,我是刑警寧澤态辛,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布麸澜,位于F島的核電站,受9級特大地震影響奏黑,放射性物質(zhì)發(fā)生泄漏炊邦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一熟史、第九天 我趴在偏房一處隱蔽的房頂上張望馁害。 院中可真熱鬧,春花似錦蹂匹、人聲如沸碘菜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽忍啸。三九已至,卻和暖如春履植,著一層夾襖步出監(jiān)牢的瞬間计雌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工玫霎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留凿滤,地道東北人。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓庶近,卻偏偏與公主長得像翁脆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鼻种,可洞房花燭夜當晚...
    茶點故事閱讀 43,554評論 2 349

推薦閱讀更多精彩內(nèi)容

  • 這篇文章是我之前翻閱了不少的書籍以及從網(wǎng)絡上收集的一些資料的整理反番,因此不免有一些不準確的地方,同時不同JDK版本的...
    高廣超閱讀 15,565評論 3 83
  • 前言 只有光頭才能變強 JVM在準備面試的時候就有看了校读,一直沒時間寫筆記。現(xiàn)在到了一家公司實習祖能,閑的時候就寫寫歉秫,刷...
    Java3y閱讀 25,496評論 11 129
  • 今天天氣不好雁芙,外面灰蒙蒙黑壓壓一片 ,瞬間要下刀子的感覺钞螟,可我的心情絲毫不受這些影響兔甘,該收拾的都已經(jīng)收拾好了,來吧...
    剽悍文霞閱讀 305評論 0 3
  • 所謂的愛情只是一場可笑的游戲鳞滨。 有很多很多的話想對你說洞焙。有很多很多的無奈想請你來幫助解決,但最終一句話拯啦。想你的感覺...
    蒙奇D路飛_3251閱讀 252評論 0 1
  • Classic sokoban game. Different styles, novel scenes, bet...
    Madelines閱讀 122評論 0 0