方法區(常量池...) 永久代 Class對象在方法區
堆---新生代(eden ,from survivor,to survivor),老年代(old)
虛擬機棧
程序計數器 線程獨佔
本地方法棧
對象的創建:內存分配:1.指針碰撞,順序整塊分配。2.空閒列表,找到足夠大小的空間分配。
對象頭【自身運行時數據(mark word 、hashcode、gc年齡、鎖標誌。。。),類型指針(對象指向其類元數據,可確 定類的大小,數組不行,不一定所有對象都有查找元數據信息不一定要根據對象本身即通過句柄)】
對象 實例數據
對齊填充
對象索引:1.句柄(不需要修改reference)。2.直接指針(速度快,節省一次指針開銷)
GC:1.引用計數器法
2.可達性分析算法(GC Roots)
虛擬機棧中引用的對象、方法區中靜態屬性引用的對象、方法區中常量引用的對象、本地方法棧中引用的對象JNI。
引用:強(不會被回收)、軟(有用但非必須,在內存溢出之前會進行二次回收)、弱(非必須,能生存到下次gc之前)、 、、、虛 (回收前給個提示)。
一個對象被回收至少經歷兩次標記,第一次可達性分析後進行篩選,篩選的條件是是否有必要執行finalize()方法,沒有重寫該方法或者已經被調用一次視爲沒必要執行。
判定一個類是否可回收:1.所以實例被回收2.加載該類的ClassLoader被回收3.該類的Class對象沒有在任何地方引用
垃圾回收算法:
1.標記-清除(效率不高,產生大量內存碎片,遇到大對象容易導致GC)
2.複製算法(內存分爲兩塊,存活對象之間複製到另外一半,然後清理,內存開銷浪費,運行高效,新生代算法8:1:1)
3.標記-整理(存活率高的情況下,效率低下。老年代算法) !!分配擔保機制,新生代空間不足直接進入老年代
安全點:gc發生在該時間點,hotspot 通過OopMap枚舉根節點
gc發生時,所有線程停頓,1.搶先式中斷(先中斷,不在安全點再恢復運行) 2.主動式中斷(設置一個標記,輪詢,爲真就掛起)
線程處於sleep或者blocked狀態不會響應中斷,這個時候需要用到 安全區域
垃圾收集器:共七中垃圾收集器,分別是serial、parnew、parallel scavenge和cms、serial old、 parallel old、G1;其中serial、parnew、parallel scavenge用於年輕代,cms、serial old、 parallel old用於年老代,g1用於年輕代和年老代。所有收集器都存在stop the world,不過在java發展中 一直在優化停頓時間。
年輕代:
Serial:適用於年輕代垃圾回收,複製算法,jdk1.3之前 推薦用於客戶端模式(Client)下的虛擬機,屬於單線程,無對stop the world優化,屬於最老的年輕代垃圾收集器產品; 單線程
ParNew:適用於年輕代垃圾回收,複製算法,jdk1.3發佈,推薦用於服務端模式(Server)下的虛擬機,屬於多線程,無對stop the world優化,其實就是Serial的多線程版本;是服務端開發的首先; 並行
Parallel Scavenge:適用於年輕代垃圾回收,複製算法,jdk1.4發佈,屬於多線程,無對stop the world優化,它是一個可以控制吞吐量的收集器,擁有自適應調節策略;需要注意一點的是,gc停頓時間縮短是犧牲吞吐量和新生代空間來換取的。 並行
stop The World:gc時 需要停止所有線程進行垃圾回收;
吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間)
自適應調節策略:虛擬機會根據當前系統的運行情況收集性能監控信息,動態調整參數以提高最合適的停頓時間或最大吞吐量。
年老代
Serial old :適用於年老代垃圾回收,標記-整理算法,jdk1.5之前,主要用於client下的虛擬機,如果用在server模式下主要有倆個作用:一是jdk1.5以及之前用於與Parallel Scavenger搭配使用,二就是爲cms提供後備預案,屬於單線程,無stop the world優化。 單線程
Parallel Old:適用於年老代垃圾回收,標記-整理算法,jdk1.6發佈,屬於多線程,注重於吞吐量控制,是爲了Parallel Scavenge定製的; 並行
CMS: 適用於年老代垃圾回收,標記-清除算法,jdk1.5發佈,推薦server模式下,屬於多線程,對stop the world有優化,CMS是一種以獲取最短回收停頓時間爲目標的收集器,也就是優化服務器響應速度。CMS分爲4步:其中 初始化標記,重新標記 stop the world
初始標記:僅僅只是標記GcRoots可以直接關聯的對象; 單線程
併發標記:進行gcroots tracing(也就是 引用鏈搜索);優化成併發 併發
重新標記:修正併發標記因用戶程序繼續運行而導致標記產生變動那一部分對象的標記記錄。 並行
併發清除:併發清理標記的對象內存。 併發
重置線程 並行
CMS缺點:
CMS對cpu資源非常敏感,默認啓動的回收線程數是(cpu數量+3)/4;垃圾回收線程數量不少於25%的cpu資源,當cpu越大,線程數/cpu總量 越小;但是當cpu小於4個時 顯得就不怎麼合適了;無法處理浮動垃圾,需要等下一次gc才能處理;並且還需要預留一部分空間提供併發收集時的用戶程序運作使用,即啓動閾值(-XX:CMSInitiatingOccupancyFraction 閾值百分比);要是CMS運行期間預留的空間不滿足程序需要,就會出現一次“Concurrent Mode Failure”失敗,這是虛擬機啓動後備預案:臨時啓用Serial Old,這樣一來停頓時間就很長了,所以-XX:CMSInitiatingOccupancyFraction 設置太高容易導致大量“Concurrent Mode Failure”失敗,性能反而降低。 由於用的是標記-清除算法,所以會出現內存碎片;CMS提供-XX:UseCMSCompactAtFullCollection開關參數(默認爲開),用於CMS收集器要進行FullGC時進行內存碎片合併整理,-XX:CMSFullGCsBeforeCompaction 用來設置執行多少次不壓縮Full GC後跟着來一次帶壓縮的(默認爲0,表示每次進入Full GC都進行碎片壓縮)。
年輕代+年老代
G1:jdk1.7發佈,整體看是“標記-整理算法”,從局部(倆個Region之間)上來看是基金“複製”算法實現,也就是說沒有內存碎片;
初始標記:僅僅只是標記GcRoots可以直接關聯的對象; 單線程
併發標記:進行gcroots tracing(也就是 引用鏈搜索); 併發
最終標記:修正併發標記因用戶程序繼續運行而導致標記產生變動那一部分對象的標記記錄。 並行
篩選回收:根據各個Region回收價值成本排序,根據用戶qi'w期望的GC時間來zhi'制定回收計劃 並行
如果應用追求低停頓,那G1現在可以作爲一個嘗試的選擇,如果應該追求吞吐量,G1並不會帶來什麼特別的好處!!!
第二部分:第四章
jdk的命令行工具簡單總結介紹
jps(Java Process State): 獲取虛擬機進程 vmid; jps options hostid
jps -v :顯示虛擬機對應啓動的參數
-q 只輸出LVMID
-m 輸出vm進程啓動時傳遞給主類main()函數的參數
-l 輸出主類全名,如果進程執行的是Jar包,輸出Jar的路徑 時間間隔 次數
jstat:虛擬機監控工具,jstat -gccause vmid:輸出已使用空間佔各自總空間的百分比; jstat options vmid interval count
[protocol:][//]lvmid[@hostname[:port]/servername]
jstat -gc 2764 250 20 每隔250ms查詢一次進程2764的gc情況,一共20次
-class 監視類裝載、卸載數量、總空間以及類裝載耗時
-gc 監視Java堆狀況,eden、survivor、老年代、永久代等容量,已用空間、GC時間合計
-gccapacity 與-gc基本相同,但輸出主要關注Java堆各個區域使用到的最大、最小空間
-gcutil 與-gc基本相同 輸出已使用空間百分比
-gccause 與-gcutil一樣 但是額外輸出導致上一次gc原因
-gcnew 監視新生代
-gcnewcapacity 與-gcnew基本相同,關注使用到的最大最小空間
-gcold
-gcoldcapacity
-gcpercapacity 永久代
-compiler 輸出JIT編譯器編譯過的方法、耗時等信息
-printcompilation 輸出已經被JIT編譯的方法
jinfo:獲取虛擬機參數值和動態修改部分運行期可改的參數。jinfo [option] pid例如:jinfo -flag PermSize vmid;顯示vid對應的虛擬機的方法區大小;jinfo -flag +/- name ,添加或刪除name屬性;
jinfo -flag name=value
jinfo -sysprops
java -XX:+PrintFlagsFinal 查看默認參數
jmap:java內存影像工具,
jmap -heap vmid:顯示堆的詳細信息,如參數配置,分代狀況;
-histo vmid:顯示堆中對象統計信息,包括類,實例數量,合計容量。
-dump 生成Java堆轉儲快照格式爲 -dump:[live,]format=b,file=<filename> live說明是否只dump存活對象
-finalizerinfo 顯示在F-Queue中等待Finalizer線程zhi 執行finalize方法的對象
-permstat 以ClassLoader爲統計口徑顯示永久代內存狀態
-F 強制生成dump快照
jhat:虛擬機堆轉儲快照分析工具; localhost:7000
jstack:java堆棧跟蹤工具; 生成線程快照:方法堆棧的集合
-F 強制輸出線程堆棧
-l 除了堆棧以外還輸出關於鎖的附加信息
-m 如果調用到本地方法還會顯示C/C++的dui'堆棧
HSDIS:JIT生成代碼反彙編
jdk的可視化工具:jConsole和visualVm;其中VisualVM有個BTrace插件值得注意。
BTrace 動態日誌跟蹤:可以打印調用堆棧、參數、返回值、性能監視、定位連接泄漏、內存泄漏、解決多線程競爭問題。如生產上遇到問題時需要方法輸入參數和返回輸出參數,但開發時沒有日記記錄,平常做法就是補充上日誌,然後在重現上線。而BTrace可以在不停止jvm的情況下動態調試代碼。(ps:BTrace後續深入研究)
推薦一篇文章:http://huanghaifeng1990.iteye.com/blog/2121419
第二部分:第五章
簡單總結:
一、jvm調優思路:
第一步:jps 獲取jvm id;
第二步:獲取jvm垃圾收集器種類
第三步:查看gc次數和時間,分析原因來優化
gc次數頻繁:①、內存回收率低導致短時間內回收次數多;②、內存大小太小;
gc時間長:①、內存過大;②、內存擴展導致時間長(固定內存大小)
選擇適合的收集器也可大幅度優化jvm。
二、優化思路注意點:
1、64位jdk的性能測試結果普遍低於32位jdk;
2、64位jdk由於指針膨脹和數據類型對齊補白導致消耗的內存比32位大;
3、使用nio時,堆外內存(direct memory)不足導致內存溢出。