Jdk:Java程序設計語言、Java虛擬機、Java API類庫。
Jdk是用於支持Java程序開發的最小環境。
Jre:Java API類庫中的Java SE API子集、Java虛擬機。
Jre是支持Java程序運行的標准環境。
Program Counter Register:較小的內存空間,可以看作當前線程所執行的字節碼的行號指示器。是唯一一個Java虛擬機規范中沒有規定OutOfMemoryError的區域。
VM Stack:生命周期和線程相同,它描述了Java方法執行的內存模型:每個方法在執行的同時都會創建一個棧幀用於存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。
兩種異常:StackOverflowError、OutOfMemoryError
Native Method Stack:類似VM Stack,且Sun HotSpot直接合二為一!
Heap:最大的一塊內存,虛擬機啟動時創建,唯一目的就是存放對象實例的。
Method Area:存儲已被虛擬機加載的類信息、常量、靜態變量、即使編譯器編譯後的代碼等數據。Java虛擬機規范稱其為堆的邏輯部分,別名卻叫Non-Heap(非堆),或永久代。
Runtime Constant Pool:方法區的一部分
Direcrt Memory:不是虛擬機運行時數據區的一部分,也不是虛擬機規范定義的內存區域。
對象的創建—關鍵字new
內存劃分方法:指針碰撞(堆內存規整,通過移動指針分配內存)、空閒列表(堆內存不規整,通過更新內存列表分配內存)。
TLAB(Thread Local Allocation Buffer):本地線程分配緩沖,對於所創建的線程都會分配一塊獨立的空間,避免內存分配沖突,提升內存分配效率。
對象的內存布局:對象頭(Header)、實例數據(Instance Data)和對其填充(Padding)。
對象的訪問定位:Java程序通過棧上的reference(引用)數據來操作堆上的具體對象。
方式:句柄和直接指針(Sun HotSpot)。
OutOfMemoryError異常實戰
工具:Eclipse Memory Analyzer
內存洩漏Memory Leak、內存溢出Memory Overflow
判斷對象是否死亡—堆內存
1、引用計數算法:給對象添加一個引用計數器,每當有一個地方引用它是,計數器加1;當引用失效時,計數器減1;任何時刻計數器為0的對象就是不可能再被使用的。
2、可達性分析算法:通過“GC Roots”對象作為起始點向下搜索,當一個對象到GC Roots沒有任何引用鏈相連,證明此對象是不可用的。
To be or not to be!
1、 使用上述算法判斷對象是否使用;
2、 如果不再被使用,則標記並篩選;
刷選是否有必要執行finalize()方法,如下情況不需要執行:
l 對象沒覆蓋finalize()方法;
l finalize()方法已經被虛擬機調用過;
3、 如果有必要執行,則把該對象放置在F-Queue隊列中;
4、 由一個虛擬機自動建立、低優先級的Finalizer線程去執行它,即由虛擬機來觸發執行;
5、 GC對隊列中的對象會進行第二次標記,即給對象重新建立引用,就能移除回收集合;
注意:任何一個對象的finalize()方法都只會被系統調用一次!
方法區回收
主要兩部分:廢棄常量和無用的類
控制參數
-Xnoclassgc:關閉虛擬機對class的垃圾回收功能;
-verbose:class:監視有多少類被加載;
-XX:TraceClassLoading、-XX:TraceClassUnLoading:打印類被加載和卸載的過程信息;
注意:在大量使用反射、動態代理、CGLib等ByteCode框架、動態生成JSP以及OSGI這類頻繁自定義ClassLoader的場景都需要虛擬機具備類卸載的功能,以保證永久代不會溢出!
垃圾收集算法
1、標記—清除算法:容易產生內存碎片
2、復制算法:堆被劃分成兩個不同的區域:新生代(Young) 主要是用來存放新生的對象、老年代(Old) 主要存放應用程序中生命周期長的內存對象。新生代 (Young)又被劃分為三個區域:Eden、From Survivor、To Survivor。
默認的,新生代(Young)與老年代(Old)的比例的值為1:2
默認的,Edem : from : to = 8 : 1 : 1
3、標記—整理算法
4、分代收集算法
HotSpot算法實現GC
枚舉根節點:逐個檢查;(Stop The World,GC執行時必須停頓所有Java執行線程)
在OopMap協助下,HotSpot可以快速並准確地完成枚舉。
安全點:只有在安全點才能停頓開始GC
安全區域:安全點的擴展,在安全區域可以停頓開始GC
垃圾收集器:內存回收的具體實現。
GC日志
GC常用參數
內存分配策略
1、對象優先在Eden分配:新生代GC(Minor GC)、老年代GC(Major GC/Full GC)
2、大對象直接進入老年代:
3、長期存活的對象將進入老年代:給每個對象定義一個年齡(Age)計數器。對象在Eden出生並經過第一次Minor GC後仍然存活,並且能被Survicor容納的話,將被移動到Survivor空間,並對象年齡設為1。對象在Survivor中每“熬過”一次Minor GC,年齡就增加1,當年齡增加到一定程度(默認15),晉升到老年代中。
4、動態對象年齡判定:虛擬機並不是永遠要求對象年齡到一定程度才能晉升老年代,如果在Survivor空間中相同年齡所有對象大小總和大於Survivor空間的一半,年齡大於或等於該年齡的對象就可以直接進入老年代。
5、空間分配擔保:老年代的連續空間大於新生代對象總大小或者歷次晉升的平均大小就會進行Minor GC,否則將進行Full GC。
工具
JDK1.5中,getAllStackTraces()用於獲取虛擬機中所有線程的StackTraceElement對象。
HSDIS:JIT生成代碼反匯編。
JConsole:Java監視與管理控制平台,基於JMX。
VisualVM:多合一故障處理工具