Java->Class->裝載-鏈接-初始化
編譯機制
1. Parse and Enter
Parse 詞法分析、語法分析
Enter 將符號輸入到符號表
2. Annotation Processing
Lombok @Getter String username; -> String getUsername();
3. Analyse and Generate
Analyse 基于抽象語法樹進行語義分析
Gen 生成class
類加載機制
裝載
鏈接
初始化
內存管理
Sun JDK在實現時遵照JVM規范,將內存空間劃分為
方法區
方法區存放了要加載的類的信息(名稱、修飾符等)、類中的靜態變量、類中定義為final類型的常量、類中的Field信息、類中的方法信息,Class對象的getName、isInterface等方法都來源于方法區域。
方法區域也是全局共享的,在一定條件下它也會被GC,當方法區域要使用的內存超過其允許的大小時,會拋出OutOfMemory的錯誤信息。
在Sun JDK中這塊區域對應Permanet Generation,又稱為持久代,默認最小值為16MB,最大值為64MB,可通過-XX:PermSize及-XX:MaxPermSize來指定最小值和最大值。
堆用于存儲對象實例及數組值。
其大小可通過-Xms和-Xmx來控制,-Xms為JVM啟動時申請的最小Heap內存,默認為物理內存的1/64但小于1GB;-Xmx為JVM可申請的最大Heap內存,默認為物理內存的1/4但小于1GB
默認當空余堆內存小于40%時,JVM會增大Heap到-Xmx指定的大小,可通過-XX:MinHeapFreeRatio=來指定這個比例;
當空余堆內存大于70%時,JVM會減小Heap的大小到-Xms指定的大小,可通過-XX:MaxHeapFreeRatio=來指定這個比例,
對于運行系統而言,為避免在運行時頻繁調整Heap 的大小,通常將-Xms和-Xmx的值設成一樣。
新生代(New Generation)
新生代由Eden Space和兩塊相同大小的Survivor Space(通常又稱為S0和S1或From和To)構成,可通過-Xmn參數來指定新生代的大小,也可通過-XX:SurvivorRatio來調整Eden Space及Survivor Space的大小。SurvivorRatio默認為8,例如當-Xmn設置為10MB時,采用串行GC,eden space即為8MB,兩個survivor space各1MB。
舊生代(Old Generation或Tenuring Generation)
用于存放新生代中經過多次垃圾回收仍然存活的對象,例如緩存對象,新建的對象也有可能在舊生代上直接分配內存。主要有兩種狀況(由不同的GC實現來決定):
一種為大對象,可通過在啟動參數上設置-XX:PretenureSizeThreshold=1024(單位為字節,默認值為0)來代表當對象超過多大時就不在新生代分配,而是直接在舊生代分配,此參數在新生代采用Parallel Scavenge GC時無效,Parallel Scavenge GC會根據運行狀況決定什么對象直接在舊生代上分配內存;
另一種為大的數組對象,且數組中無引用外部對象。
舊生代所占用的內存大小為-Xmx對應的值減去-Xmn對應的值。
本地方法棧
本地方法棧用于支持native方法的執行,存儲了每個native方法調用的狀態,在Sun JDK的實現中本地方法棧和JVM方法棧是同一個。
PC寄存器和JVM方法棧
每個線程均會創建PC寄存器和JVM方法棧
PC寄存器占用的可能為CPU寄存器或操作系統內存,
JVM方法棧占用的為操作系統內存,
JVM方法棧為線程私有,其在內存分配上非常高效。當方法運行完畢時,其對應的棧幀所占用的內存也會自動釋放。
當JVM方法棧空間不足時,會拋出StackOverflowError的錯誤,在Sun JDK中可以通過-Xss來指定其大小

內存回收
強引用
A a=new A();就是一個強引用,強引用的對象只有在主動釋放了引用后才會被GC。

軟引用(SoftReference)
采用軟引用來建立引用的對象,當JVM內存不足時會被回收,因此SoftReference很適合用于實現緩存。
另外,當GC認為掃描到的SoftReference不經常使用時,也會進行回收,存活時間可通過-XX:SoftRefLRUPolicyMSPerMB來進行控制,其含義為每兆堆空閑空間中SoftReference的存活時間,默認為1秒。
Object object=new Object();  
SoftReference<Object> softRef=new SoftReference<Object>(object);  
object=null; 
當需要獲取時,可通過softRef.get來獲取,值得注意的是softRef.get有可能會返回null。

弱引用(WeakReference)
采用弱引用建立引用的對象沒有強引用后,GC時即會被自動釋放。
WeakReference的使用方法如下:
Object object=new Object();  
WeakReference<Object> weakRef=new WeakReference<Object>(object);  
object=null; 
當需要獲取時,可通過weakRef.get來獲取,值得注意的是weakRef.get有可能會返回null。
可傳入一個ReferenceQueue對象到WeakReference的構造器中,當object對象被標識為可回收時,執行weakRef.isEnqueued會返回true。

虛引用(PhantomReference)
采用虛引用可跟蹤到對象是否已從內存中被刪除。
PhantomReference的使用方法如下:
Object object=new Object();  
ReferenceQueue<Object> refQueue=new ReferenceQueue<Object>();  
PhantomReference<Object> ref=new PhantomReference<Object>(object,refQueue);  
object=null; 
值得注意的是ref.get永遠返回null,當object從內存中刪除時,調用ref.isEnqueued()會返回true。

調優工具
jstat -class pid
顯示加載class的數量,及所占空間等信息。
C:\Users\Administrator>jstat -class 3988
Loaded  Bytes  Unloaded  Bytes     Time
 22628 50486.8        0     0.0      40.41
 
jstat -compiler pid
顯示VM實時編譯的數量等信息。
C:\Users\Administrator>jstat -compiler 3988
Compiled Failed Invalid   Time   FailedType FailedMethod
    5442      4       0   160.18          1 org/jaxen/expr/DefaultNameStep evaluate
 
jstat -gc pid
顯示gc的信息,查看gc的次數,及時間。其中最后五項,分別是young gc的次數,young gc的時間,full gc的次數,full gc的時間,gc的總時間。
C:\Users\Administrator>jstat -gc 3988
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT
33408.0 34112.0  0.0   4758.9 279424.0 22954.7   699072.0   406620.2  262144.0 181978.0     45    1.556   5      5.653    7.209
 
jmap pid
打印內存使用的摘要信息
jmap –heap pid
java heap信息
C:\Users\Administrator>jmap -heap 3988
Attaching to process ID 3988, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 20.6-b01
using thread-local object allocation.
Parallel GC with 4 thread(s)
Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 1073741824 (1024.0MB)
   NewSize          = 1310720 (1.25MB)
   MaxNewSize       = 17592186044415 MB
   OldSize          = 5439488 (5.1875MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 21757952 (20.75MB)
   MaxPermSize      = 268435456 (256.0MB)
Heap Usage:
PS Young Generation
Eden Space:
   capacity = 286130176 (272.875MB)
   used     = 23770864 (22.669662475585938MB)
   free     = 262359312 (250.20533752441406MB)
   8.307709565033784% used
From Space:
   capacity = 34930688 (33.3125MB)
   used     = 4873136 (4.6473846435546875MB)
   free     = 30057552 (28.665115356445312MB)
   13.950873226430582% used
To Space:
   capacity = 34209792 (32.625MB)
   used     = 0 (0.0MB)
   free     = 34209792 (32.625MB)
   0.0% used
PS Old Generation
   capacity = 715849728 (682.6875MB)
   used     = 416379120 (397.09007263183594MB)
   free     = 299470608 (285.59742736816406MB)
   58.16571603139591% used
PS Perm Generation
   capacity = 268435456 (256.0MB)
   used     = 186345512 (177.71292877197266MB)
   free     = 82089944 (78.28707122802734MB)
   69.41911280155182% used
C:\Users\Administrator>

jmap -histo:live pid
統計對象count ,live表示在使用
jmap -histo:live 3988
jmap -histo pid >mem.txt
打印比較簡單的各個有多少個對象占了多少內存的信息到重定向的文件
C:\Users\Administrator>jmap -histo 3988 >mem.txt
C:\Users\Administrator>notepad mem.txt
jmap -dump:format=b,file=mem.dat pid
將內存使用的詳細情況輸出到mem.dat 文件
用jhat命令可以參看
jhat -port 7000 mem.dat 然后使用:http://localhost:7000/查看類相關信息
C:\Users\Administrator>jmap -dump:format=b,file=mem.dat 3988
Dumping heap to C:\Users\Administrator\mem.dat ...
Heap dump file created
C:\Users\Administrator>jhat -port 7000 mem.dat
Reading from mem.dat...
Dump file created Wed Apr 25 12:51:50 CST 2012
Snapshot read, resolving...
Resolving 4512527 objects...
Chasing references, expect 902 dots...............
..................................................
Eliminating duplicate references..................
..................................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.