程序計數器:java
棧:數據庫
本地方法棧:數組
堆:緩存
方法區:安全
直接內存:多線程
棧幀:一個方法對應一個棧幀區域,先進後出FILO,壓棧再出棧。運維
操做數棧:是各類運算髮生的場所,各類數據在進行運算時都會彈入操做數棧,而後結果會彈出操做數棧。jvm
方法出口:存儲的是當前方法執行完畢以後應該返回到上一級方法的位置。佈局
方法區又稱永久代在1.8稱爲元空間。性能
一、Java7及之前版本的Hotspot中方法區位於永久代中。同時,永久代和堆是相互隔離的,但它們使用的物理內存是連續的。永久代的垃圾收集是和老年代捆綁在一塊兒的,所以不管誰滿了,都會觸發永久代和老年代的垃圾收集。
二、元空間存在於本地內存,意味着只要本地內存足夠,它不會出現像永久代中「java.lang.OutOfMemoryError: PermGen space」這種錯誤。看上圖中的方法區,是否是「膨脹」了。默認狀況下元空間是能夠無限使用本地內存的,但爲了避免讓它如此膨脹,JVM一樣提供了參數來限制它使用的使用。
表面上看是爲了不OOM異常。由於一般使用PermSize和MaxPermSize設置永久代的大小就決定了永久代的上限,可是不是總能知道應該設置爲多大合適, 若是使用默認值很容易遇到OOM錯誤。當使用元空間時,能夠加載多少類的元數據就再也不由MaxPermSize控制, 而由系統的實際可用空間來控制。 更深層的緣由仍是要合併HotSpot和JRockit的代碼,JRockit歷來沒有所謂的永久代,也不須要開發運維人員設置永久代的大小,可是運行良好。同時也不用擔憂運行性能問題了,在覆蓋到的測試中, 程序啓動和運行速度下降不超過1%,可是這點性能損失換來了更大的安全保障。
總結:
-XX:MetaspaceSize,class metadata的初始空間配額,以bytes爲單位,達到該值就會觸發垃圾收集進行類型卸載,同時GC會對該值進行調整:若是釋放了大量的空間,就適當的下降該值;若是釋放了不多的空間,那麼在不超過MaxMetaspaceSize(若是設置了的話),適當的提升該值。 -XX:MaxMetaspaceSize,能夠爲metadata分配的最大空間,默認是沒有限制的。 -XX:MinMetaspaceFreeRatio,在GC以後,最小的Metaspace剩餘空間容量的百分比。 -XX:MaxMetaspaceFreeRatio,在GC以後,最大的Metaspace剩餘空間容量的百分比。
Class能夠理解爲Class文件的資源倉庫.class文件中除了包含類的版本、字段、方法、接口等描述信息,還有一項就是常量池,常量池中用於存放編譯期間生成的各類字面變量和符號引用。
八中基本類型中byte、short、integer、long、char等在值小於等於127使用對象池,即不負責建立和管理大於127的對象。
例子:
String s1 = "abc"; String s2 = "abc"; String s3 = new String("abc"); String s4 = new String("abc"); s1==s2 s2!=s3 s3!=s4
例題1:String str=new String("abc");建立了多少個對象?
答:建立過程以下:
所以,常量池沒有"abc"字面量則建立兩個對象,不然建立一個對象以及建立一個對象的引用。
例題2:String str=new String("a"+"b");建立了多少個對象?
答:字符串常量池:a、b、ab。
堆:new String("ab")。
引用:str。
合計5個。
TLAB(Thread Local Allocation Buffer)線程本地分配緩衝區。
JVM分配對象是優先分配到線程棧上,棧上分配不了的(如對象較大)則直接分配在Old區;若是對象不大,優先分配在棧上的TLAB上。
TLAB是在Eden區的專門的內存空間,爲了防止在Eden區分配空間的多線程競爭資源,JVM爲每一個線程在Eden區上分配的專屬內存空間即TLAB。
Java Object Layout 對象的內存佈局:即對象在內存中如何分佈的。
數組對象:markword(8) + classPointer(4) + 數組長度(4) + 實例數據 + 對齊
Ps:壓縮指針和壓縮普通對象指針:使用java -XX:+PrintCommandLineFlags -version命令能夠看到包含如下信息:
顯示: -XX:+UseCompressedClassPointers -XX:+UseCompressedOops,
其中-XX:+UseCompressedClassPointers是使用壓縮類指針,原先是8字節,因爲8字節=8x8=64位,2^64位尋址空間太大,所以不必使用8字節,所以使用了壓縮成4字節的壓縮指針,4字節的尋址能力:48=32位,2^32=4G(2^10=1024=1KB 2^20=1M 2^30=1G) 又因爲JVM是8字節一尋址,也就是每8字節做爲一個單位,所以實際尋址能力4G8=32G,ZGC號稱最大可以使用4T的內存,ZGC使用8字節做爲ClassPointer 其中有42位爲類指針,4位爲顏色指針,2^42=4T。
其中-XX:+UseCompressedOops是表示使用壓縮對象指針進行尋址,兩個指令應該是一對的。
關閉壓縮指針-XX:-UseCompressedClassPointers -XX:-UseCompressedOops指令。
CAS保證,每一個線程在jvm預先分配了內存,稱爲本地線程分配緩衝區TLAB,並同步鎖定。
棧上的reference數據操做具體堆上的對象有句柄和直接指針兩種方式。
句柄方式:jvm堆上劃份內存來做爲句柄池,引用時引用存儲對象的句柄地址,句柄中包含對象實例數據和類型數據的各自具體地址信息。
優勢:引用不用修改,比較穩定,對象移動如垃圾回收只要改變句柄值便可。
直接指針:引用直接引用對象地址,對象中包含類型數據指針,指向方法區class。
優勢:速度快。
其中二、3兩部會發生指令重排。
JVM的3中運行模式:
解釋模式:只使用解釋器,執行一行JVM字節碼就編譯一行爲機器碼。這樣能更快的看到程序的執行效果,可是執行的效果並不必定最快。適合執行一次的代碼模塊。
編譯模式:只使用編譯器,先將全部的JVM字節碼一次編譯爲機器碼,而後一次性執行全部機器碼。這樣啓動的稍慢,但執行完很快,適合反覆執行的代碼模塊;
混合模式:依然採用解釋模式,可是對於一點熱點代碼採用編譯模式,並把對應的字節碼緩存起來。JVM通常採用混合模式。
對象逃逸分析:
public User t1(){ User user = new User(); user.setId(1); user.setName("sz"); //寫入數據庫 return user; } public User t2(){ User user = new User(); user.setId(1); user.setName("sz"); //寫入數據庫 }
t1對象會被其餘引用,做用範圍不明顯;t2對象不會被其餘線程引用,直接分配到當前線程。
對象逃逸分析的JVM參數: -XX:+DoEscapeAnalysis(開啓)-XX:DoEscapeAnalysis(關閉)。
JDK1.7以後默認開啓,但若是棧空間不足會分配到堆空間。逃逸分析發生在編譯期間。