JVM學習筆記-01

是馬壯啊發表於2020-12-05

一、JVM記憶體模型

在這裡插入圖片描述

1.Java堆(Heap)

是Java虛擬機器所管理的記憶體中最大的一塊。Java堆是被所有執行緒共享的一塊記憶體區域,在虛擬機器啟動時建立。此記憶體區域的唯一目的就是存放物件例項,幾乎所有的物件例項都在這裡分配記憶體。

2.方法區(Method Area)

方法區(Method Area)與Java堆一樣,是各個執行緒共享的記憶體區域,它用於儲存已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料。

3.程式計數器(Program Counter Register)

程式計數器(Program Counter Register)是一塊較小的記憶體空間,它的作用可以看做是當前執行緒所執行的位元組碼的行號指示器。

4.虛擬機器棧(JVM Stacks)

與程式計數器一樣,Java虛擬機器棧(Java Virtual Machine Stacks)也是執行緒私有的,它的生命週期與執行緒相同。虛擬機器棧描述的是Java方法執行的記憶體模型:每個方法被執行的時候都會同時建立一個棧幀(Stack Frame)用於儲存區域性變數表、運算元棧、動態連線、 方法返回地址。每一個方法被呼叫直至執行完成的過程,就對應著一個棧幀在虛擬機器棧中從入棧到出棧的過程。

5.本地方法棧(Native Method Stacks)

本地方法棧(Native Method Stacks)與虛擬機器棧所發揮的作用是非常相似的,其區別不過是虛擬機器棧為虛擬機器執行Java方法(也就是位元組碼)服務,而本地方法棧則是為虛擬機器使用到的Native方法服務。

二、 JVM的生命週期

1.啟動:

啟動一個Java程式時,一個JVM例項就產生了,任何一個擁有public static voidmain(String[] args)函式的class都可以作為JVM例項執行的起點。

2.執行:

main()作為該程式初始執行緒的起點,任何其他執行緒均由該執行緒啟動。JVM內部有兩種執行緒:守護執行緒和非守護執行緒,main()屬於非守護執行緒,守護執行緒通常由JVM自己使用,java程式也可以表明自己建立的執行緒是守護執行緒。

3消亡:

當程式中的所有非守護執行緒都終止時,JVM才退出;若安全管理器允許,程式也可以使用Runtime類或者System.exit()來退出。

三、JVM記憶體

Java把記憶體分兩種:棧記憶體和堆記憶體。簡單來講,堆記憶體用於存放有new建立的物件和陣列,在堆中分配的記憶體,有java虛擬機器自動垃圾回收器來管理。而棧記憶體由使用的人向系統申請,申請人進行管理。

JVM堆記憶體

年輕代(YoungGen)、老年代(OldGen)
年輕代兩部分:
Eden(生成區)、Survivor(倖存區)
Survivor兩部分:FromSpace、ToSpace
Eden區佔大容量,
Eden:From Survivor:To Survivor預設比例8:1:1。

JVM非堆記憶體(方法區)

jdk8之前,存在著永久代/持久代(PermGen)
jdk8,永久代被元空間(meatspace)取代。但是元空間並不在虛擬機器中,而是使用本地記憶體。因此,預設情況下,元空間的大小僅受本地記憶體限制。
為什麼用元空間取代永久代?
字串存在永久代中,容易出現效能問題和記憶體溢位
為融合HotSpot JVM與JRockit JVM(新JVM技術)而做出的改變

記憶體申請過程:

VM會試圖為相關Java物件在年輕代的Eden區中初始化一塊記憶體區域。
當Eden區空間足夠時,記憶體申請結束。否則執行下一步。
JVM試圖釋放在Eden區中所有不活躍的物件(Young GC)。釋放後若Eden空間仍然不足以放入新物件,JVM則試圖將部分Eden區中活躍物件放入Survivor區。
Survivor區被用來作為Eden區及年老代的中間交換區域。當年老代空間足夠時,Survivor區中存活了一定次數的物件會被移到年老代。
當年老代空間不夠時,JVM會在年老代進行完全的垃圾回收(Full GC)。
Full GC後,若Survivor區及年老代仍然無法存放從Eden區複製過來的物件,則會導致JVM無法在Eden區為新生成的物件申請記憶體,即出現“Out of Memory”。

四、Java中的四種引用型別級別

物件的引用四種級別由高到低:強引用、軟引用、弱引用、虛引用

1.強引用

我們寫程式碼使用的物件就是強引用,它有其他物件或方法、變數等等指向它的引用
如果一個物件被擁有強引用,那麼垃圾回收器絕不會回收它。當記憶體空間不足,Java 虛擬機器寧願丟擲 OutOfMemoryError 錯誤,使程式異常終止,也不會靠隨意回收具有強引用的物件來解決記憶體不足問題。

2.軟引用

如果一個物件只具有軟引用,那麼如果記憶體空間足夠,垃圾回收器就不會回收它,如果記憶體空間不足了,就會回收這些物件的記憶體。只要垃圾回收器沒有回收它,該物件就可以被程式使用。軟引用可用來實現記憶體敏感的快取記憶體。
軟引用可以和一個引用佇列(ReferenceQueue)聯合使用,如果軟引用所引用的物件被垃圾回收,Java 虛擬機器就會把這個軟引用加入到與之關聯的引用佇列中。

3.弱引用

如果一個物件只具有弱引用,那該類就是可有可無的物件,因為只要該物件被 gc 掃描到了隨時都會把它幹掉。弱引用與軟引用的區別在於:只具有弱引用的物件擁有更短暫的生命週期。在垃圾回收器執行緒掃描它所管轄的記憶體區域的過程中,一旦發現了只具有弱引用的物件,不管當前記憶體空間足夠與否,都會回收它的記憶體。不過,由於垃圾回收器是一個優先順序很低的執行緒, 因此不一定會很快發現那些只具有弱引用的物件。
弱引用可以和一個引用佇列(ReferenceQueue)聯合使用,如果弱引用所引用的物件被垃圾回收,Java 虛擬機器就會把這個弱引用加入到與之關聯的引用佇列中。
如果一個物件只具有弱引用,那該類就是可有可無的物件,因為只要該物件被 gc 掃描到了隨時都會把它幹掉。弱引用與軟引用的區別在於:只具有弱引用的物件擁有更短暫的生命週期。在垃圾回收器執行緒掃描它所管轄的記憶體區域的過程中,一旦發現了只具有弱引用的物件,不管當前記憶體空間足夠與否,都會回收它的記憶體。不過,由於垃圾回收器是一個優先順序很低的執行緒, 因此不一定會很快發現那些只具有弱引用的物件。

4.虛引用

"虛引用"顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用並不會決定物件的生命週期。如果一個物件僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收。虛引用主要用來跟蹤物件被垃圾回收的活動。
虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用佇列(ReferenceQueue)聯合使用。當垃圾回收器準備回收一個物件時,如果發現它還有虛引用,就會在回收物件的記憶體之前,把這個虛引用加入到與之關聯的引用佇列中。程式可以通過判斷引用佇列中是否已經加入了虛引用,來了解被引用的物件是否將要被垃圾回收。程式如果發現某個虛引用已經被加入到引用佇列,那麼就可以在所引用的物件的記憶體被回收之前採取必要的行動。

常用引數

-verbose:class
輸出jvm載入類的相關資訊,當jvm報告說找不到類或者類衝突時可此進行診斷。
-verbose:gc
輸出每次GC的相關情況。
-verbose:jni
輸出native方法呼叫的相關情況,一般用於診斷jni呼叫錯誤資訊。

-Xms512m
設定JVM初始記憶體為512m。此值可以設定與-Xmx相同,以避免每次垃圾回收完成後JVM重新分配記憶體。
-Xmx512m
設定JVM最大可用記憶體為512M。
-Xmn200m
設定年輕代大小為200M。整個堆大小=年輕代大小 + 年老代大小 + 持久代大小。持久代一般固定大小為64m,所以增大年輕代後,將會減小年老代大小。此值對系統效能影響較大,Sun官方推薦配置為整個堆的3/8。
-Xss128k
設定每個執行緒的堆疊大小。JDK5.0以後每個執行緒堆疊大小為1M,以前每個執行緒堆疊大小為256K。更具應用的執行緒所需記憶體大小進行調整。在相同實體記憶體下,減小這個值能生成更多的執行緒。但是作業系統對一個程式內的執行緒數還是有限制的,不能無限生成,經驗值在3000~5000左右。
-Xloggc:file
與-verbose:gc功能類似,只是將每次GC事件的相關情況記錄到一個檔案中,檔案的位置最好在本地,以避免網路的潛在問題。
若與verbose命令同時出現在命令列中,則以-Xloggc為準。
-Xprof
跟蹤正執行的程式,並將跟蹤資料在標準輸出輸出;適合於開發環境除錯。

效能調優引數列表:

引數及其預設值
描述
-XX:LargePageSizeInBytes=4m
設定用於Java堆的大頁面尺寸
-XX:MaxHeapFreeRatio=70
GC後java堆中空閒量佔的最大比例
-XX:MaxNewSize=size
新生成物件能佔用記憶體的最大值
-XX:MaxPermSize=64m
老生代物件能佔用記憶體的最大值
-XX:MinHeapFreeRatio=40
GC後java堆中空閒量佔的最小比例
-XX:NewRatio=2
新生代記憶體容量與老生代記憶體容量的比例
-XX:NewSize=2.125m
新生代物件生成時佔用記憶體的預設值
-XX:ReservedCodeCacheSize=32m
保留程式碼佔用的記憶體容量
-XX:ThreadStackSize=512
設定執行緒棧大小,若為0則使用系統預設值
-XX:+UseLargePages
使用大頁面記憶體

相關文章