分析和輸入到符號表:
詞法分析:將代碼轉化爲token序列
語法分析:由token序列生成抽象語法樹
輸入到符號表:將類中出現的符號輸入到類的符號表java
註解處理:
處理用戶自定義註解,以後繼續第一步算法
根據符號表進行語義分析並生成class文件,並進行相關優化數組
虛擬機數據類型、字節碼文件格式、虛擬機指令集緩存
雙親委派、線程上下文類加載器、Web容器、OSGi:
http://www.ibm.com/developerworks/cn/java/j-lo-classloader/多線程
校驗:校驗二進制字節碼格式是否符合Java Class File Format規範
準備:爲類的靜態屬性分配內存和默認值,並加載引用的類或接口
解析:將運行時常量池中的符號引用替換爲直接引用(靜態綁定)併發
類的初始化時機:
1) 建立類的實例
2) 初始化某個類的子類(知足主動調用,即訪問子類中的靜態變量、方法)
3) 反射(Class.forName()會觸發,ClassLoader.loadClass()及X.class不會觸發)
4) 訪問類或接口的靜態變量(static final常量除外,static final變量能夠)
5) 調用類的靜態方法
6) java虛擬機啓動時被標明爲啓動類的類app
初始化順序:
父類靜態成員、靜態代碼塊—>子類靜態成員、靜態代碼塊—>父類和子類實例成員內存分配—>父類實例成員、代碼塊—>父類構造函數—>子類實例成員、代碼塊—>子類構造函數jvm
運行時數據區:函數
JVM在Eden區分配一塊內存爲TLAB,在TLAB建立對象時不須要加鎖,因此JVM首先在TLAB上建立對象,不夠則在堆上建立。
性能
靜態綁定、動態綁定:
http://hxraid.iteye.com/blog/428891
對象:對象頭、對象體、字節填充
對象頭:
http://blog.csdn.net/bingjing12345/article/details/8642595
對象頭的MarkWord用於存儲對象的各類標記信息,實現鎖、 哈希算法、垃圾回收等。
後續爲指向類方法區的引用及數組長度(若爲數組)。
a. 堆上分配:指針碰撞、間隙列表
b. 棧上分配:基於逃逸分析
c. 堆外分配:Unsafe.allocateMemory()、DirectByteBuffer、ByteBuffer.allocateDicrect()或MappedByteBuffer
d. TLAB分配:Thread Local Allocation Buffer,多線程環境中JVM在Eden區分配一塊內存爲TLAB,在TLAB建立對象時不須要加鎖,因此JVM首先在TLAB上建立對象,不夠則在堆上建立。可經過-XX:TLABWasteTargetPercent設置TLAB和Eden的比例,可經過-XX:+PrintTLAB查看TLAB的使用狀況。
引用計數器:爲每一個對象分配一個引用計數器,當計數器爲0時回收對象,缺點:循環引用問題
複製:從根集合掃描存活對象,複製到一塊全新內存空間,缺點:須要2倍內存空間,存活對象較多時開銷較大
標記-清除:從根集合掃描並標記存活對象,掃描完成後清除未標記對象,缺點:存活對象較少時內存碎片較多
標記-清除-壓縮:從根集合掃描並標記存活對象,掃描完成後將存活對象移動並對齊
分代回收:根據生命週期長短,把JVM堆分紅新生代、老年代。
說明:根集合範圍爲Java堆中的對象(Card Table/Remember Set)、方法區中的靜態對象、Java棧中的局部變量表和JNI句柄指向的對象。
-Xmx:設置最大堆內存,即新生代、老年代之和的最大值,該參數設置太小會觸發OOM
-Xms:設置最小堆內存,即JVM啓動時的初始堆大小,通常設置和-Xmx相同,避免垃圾回收後JVM內存重分配
-XX:NewSize:設置新生代的初始值
-XX:MaxNewSize:設置新生代最大值
-Xmn:等同於設置相同的-XX:NewSize和-XX:MaxNewSize,該參數設置太小會頻繁GC
-XX:PermSize:設置持久代初始值
-XX:MaxPermSize:設置持久代最大值
-Xss:設置線程棧大小
-XX:NewRatio:設置老年代與新生代的比例
-XX:SurvivorRatio:設置Eden區與S區的比例
-XX:MaxTenuringThreshold:設置垃圾回收最大年齡,即新生代中的對象通過多少次複製進入老年代
-XX:PretenureSizeThreshold:設置大於指定大小的較大對象直接進行老年代
-XX:TargetSurvivorRatio:設置S區的可以使用率,當S區的空間使用率達到這個數值,會將對象送入老年代
-XX:MinHeapFreeRatio:設置堆空間的最小空閒比例,當堆空間的空閒內存小於這個數值時,JVM便會擴展堆空間
-XX:MaxHeapFreeRatio:設置堆空間的最大空閒比例,當堆空間的空閒內存大於這個數值時,JVM便會壓縮堆空間
新生代串行GC:使用複製算法,單線程STW
新生代並行回收GC:使用複製算法,多線程STW,吞吐量優先:自動調整新生代Eden、S0、S1大小
新生代並行GC:使用複製算法,多線程STW,新生代串行GC的多線程版本
老年代串行GC:使用標記壓縮算法,單線程STW
老年代並行回收GC:使用標記壓縮算法,多線程STW ,壓縮方式比較特別,內存按線程數劃分紅不一樣區域,壓縮時根據區域存活對象比例決定是否整塊壓縮
老年代併發GC:使用標記清除算法。問題:① 佔用更多CPU;② 浮動垃圾;③ 內存碎片:支持Full GC後的碎片整理清除,多線程不STW,可是碎片整理是STW;
說明:
① -XX:+UserSerialGC爲client默認方式,-XX:+UseParallelOldGC爲server默認方式;
② 分存分配方式:指針碰撞(bump-the-pointer)、空閒列表(free list)、TLAB;
③ 根集合掃描加速:Card Table、Mod Union Table、Remembered Set;
④ 新生代並行回收GC沒有對Mod Union Table進行處理,所以不能和老年代併發GC一塊兒工做;
⑤ 使用 -XX:+HeapDumpOnOutOfMemoryError開啓堆Dump;
優化方案:
① 給新生代分配較大空間,由於Full GC比Mirror GC成本高;
② 新生代進入老年代的年齡設置較大值,緣由同上;
③ 設置大對象直接進入老年代,由於新生代使用複製算法,而且佔用兩倍空間,大對象成本高;
④ 最大和最小堆大小設置成同樣,避免堆的調整;
⑤ 吞吐量優先模式:並行回收GC;
⑥ 響應時間優先模式:併發GC;
1) 棧頂緩存:將操做數棧頂中值直接緩存在寄存器上,計算後放回操做數棧
2) 部分棧幀共享:調用方法時,後一方法可將前一方法的操做數棧做爲當前方法的局部變量,節省數據拷貝消耗
對頻繁執行的代碼編譯爲機器碼,對不頻繁執行的代碼繼續使用解釋方式,可經過CompileThreshold、OnStackReplacePercentage兩個計數器進行配置
1) client編譯(C1):
方法內聯:方法較短時,將被調用方法的指令直接植入當前方法
去虛擬化:如發現類中的方法只提供一個實現類,則對調用方進行內聯
冗餘削除:根據運行時情況對代碼進行摺疊或削除
2) server編譯(C2):
經過運行時信息,如分支判斷(優先執行頻率高的分支)和逃逸分析(變量是否被外部讀取)等進行優化
標量替換:未用到對象的所有變量時,用標量替換聚合量,避免建立對象,節省內存,優化執行
棧上分配:對象未逃逸時,直接在棧上建立對象,優化執行
同步削除:對象未逃逸時,C2直接去掉同步
3) OSR編譯(On-Stack Replacement):
只在循環代碼體部分編譯,其它部分仍然是解釋執行
C一、C2不知足優化條件時,進行逆優化回到解釋執行模式
1) 因爲權限校驗、全部方法掃描及Method對象的複製,getMethod()方法比較消耗性能,應該緩存返回的Method對象;2) Method.invoke()的性能瓶頸:參數的數組包裝、方法可見性檢查、參數的類型檢查。可經過JDK7的MethodHandle提升性能;