jvm
使用軟件模擬java字節碼的指令集
jvm的發展歷史
- 1996年jdk1.0(sun)發佈 :純解釋運行
- 1997年jdk1.1發佈,AWT、內部類、jdbc、rmi、反射
- 1998年jdk1.2發佈,java分se、me、ee,加入swing
- 2000年jdk1.3發佈,Hotspot作爲默認虛擬機
- 2002年jdk1.4發佈,classic vm退出歷史,加入assert、nio、ipv6、日誌
- 2004年jdk1.5發佈,加入泛型、註解、枚舉、裝箱、變長參數、foreach
- 2006年jdk1.6發佈,加入腳本語言支持、jdbc4.0
- 2011年jdk1.7發佈,加入動態語言增強、nio2.0、加入G1
- 2014年jdk1.8發佈,lambda表達式,函數式編程
jvm運行機制
1. java xxx 執行運行命令
2. 裝載配置(jvm.cnf)
3. 尋找dll(jvm.dll爲java虛擬機的主要實現)
4. 初始化jvm(JNIEnv爲jvm接口,findClass通過它實現)
5. 找到mian方法並運行
jvm的內部結構
pc寄存器
每個線程都有一個獨立的pc寄存器
方法區
保存裝載的類信息
java堆
應用系統對象保存、所有線程共享堆、gc的主要工作空間、堆也是分代的(分代gc)
java棧
線程私有,棧由一些列幀組成、幀保存一個方法的局部變量、操作數棧、常量池指針,每一個方法調用創建一個幀、並壓棧
可見性
一個線程修改了變量,其他線程可以立即知道
保證可見性方式
volatile
synchronized unlock之前,將變量值寫會主存
final 一旦初始化完成,其他線程可見
有序性
本線程內,操作都是有序的
在線程外觀察,操作都是無序的(指令重排或者主存延時)
指令重排
保證線程內按順序執行的結果完全相同
指令重排原則:
順序原則:一個線程內保證語義的串行性
volatile規則:volatile變量的寫,先發生於讀
鎖規則:解鎖必然發生於隨後的加鎖前
傳遞性:a先於b,b先於c,則a必然先於c
線程的start先於他的每一個動作
線程的所有操作先於線程的終結
線程的中斷先於被中斷的線程的代碼
對象的構造函數的執行結束先於finalize()方法
jvm的配置參數
trace跟蹤參數
-verbose:gc (打開gc跟蹤日誌)
-XX:+PrintGC 打印gc簡要信息
-XX:+PrintGCDetails 打印gc詳細信息
-XX:+PrintGCTimeStamps 打印gc發生的時間戳
-Xloggc:log/gc.log 指定gc的log文件的位置
-XX:+PrintHeapAtGC 每一個gc後,打印堆信息
-XX:+TraceClassLoading 監控類的加載
-XX:+PrintClassHistogram 按下ctrl+break後,打印類的信息(分別顯示:序號、實例數量、總大小、類型)
堆的分配參數
-Xmx -Xms 指定最大堆和最小堆空間
-Xmx20m 最大可用20m
-Xms5m 初始化佔用5m
-Xmn 設置新生代的大小的絕對值
-XX:NewRatio 設置新生代的大小比例(設置4 表示 新生代:老年代=1:4,即年輕代佔堆的1/5) 官方推薦佔3/8
-XX:SurvivorRatio 設置兩個survivor和Eden的比(設置8 表示s:e=2:8,即一個survivor佔年輕代的1/10) 官方推薦佔1/10
-XX:HeapDumpOnOutOfMenoryError 發生內存溢出時導出堆到文件
-XX:+HeapDumpPath 設置發生內存溢出導出文件的路徑
-XX:OnOutOfMenoryError 在發生內存溢出時執行一個腳本
永久區分配參數
-XX:PermSize 設置永久區的大小
-XX:MaxPermSize 設置永久區的最大空間大小
如果堆空間未使用完,發生了內存溢出,則有可能是永久代內存溢出
棧大小的分配
通常只有幾百k
、決定了函數調用的深度
、每個線程都有獨立的棧空間
、局部變量、參數分配在棧上
-Xss 分配棧空間的大小(e:-Xss128k)
GC算法和種類
GC:垃圾回收,GC的回收目標是堆空間和永久區
引用計數法
通過引用計算來回收垃圾
爲每個對象設計一個引用計數器,如果有對象引用該對象,則計數加1,引用釋放,則計數減1
比較影響性能,始終都伴隨着應用加和減
很難處理循環引用
java中沒有被使用
標記-清除算法
現代垃圾回收算法的思想基礎
分爲標記階段(通過根節點,標記所有從根節點開始的可達對象,未被標記的對象即是垃圾對象)和清除階段(清除所有未被標記的對象)
標記-整理算法
適用於存活對象較多的場合,如老年代
從根節點開始,對所有可達對象做一次標記,之後將所有存活對象整理到內存的一端,然後清理邊界外的所有空間
複製算法
是一種相對高效的算法
不適用於存活對象較多的場合
將原有空間分爲兩塊,每次只使用其中一塊,垃圾回收時,將正在使用的內存中的存活對象複製到未使用的內存中,之後清除正在使用塊的所有對象,然後交換兩個內存角色
比較浪費空間
分代思想
依據對象的存活週期,存活時間短的歸爲新生代,存活時間長的對象爲老年代
根據不同代的特點,選取合適的收集算法(少量對象存活,適合複製算法)(大量對象存活,適合標記清除和標記整理)
可觸及性
可觸及的:從根節點可以觸及到這個對象
可復活的:一旦所有引用被釋放,就是可復活狀態
在調用finalize()中可能復活的對象
不可觸及的:執行finalize()之後會進入不可觸及狀態
不可觸及的對象不可能復活
可以被垃圾回收器回收
finalize()方法只會被調用一次,在第一次執行gc調用,之後的gc操作不會調用finalize()
注意事項
避免使用finalize(),操作不慎可能導致錯誤
gc的調用不確定
可以使用try-catch-finally處理資源的釋放
根節點
棧中引用的對象
方法區中靜態成員或者常量引用的對象
JNI(java native 方法)方法棧中引用的對象
Stop-The-World
java中一種全局暫停的現象
全局停頓,所有java代碼停止,native代碼可執行,但不能和jvm交互
多半由於gc引起(dump線程,死鎖檢查,堆dump也可能引起)
可能會導致(長時間停止服務,沒有響應 高可用系統中可能會引起主備切換,危害生產環境)
GC參數
串行回收器
最古老,最穩定,效率高,可能會產生比較長的停頓
-XX:+UseSerialGC //串行回收器
//新生代,老年代會使用串行回收
//新生代使用的是複製算法
//老年代使用的是標記-整理算法
並行收集器
ParNew收集器
-XX:+UseParNewGC //並行回收器
//新生代並行,老年代串行
//Serial收集器新生代的並行版本
//使用複製算法
//多線程性能比較好,需要多核支持
-XX:ParallelGCThreads //限制線程數量
parallel收集器
//類似ParNew
//新生代使用複製算法
//老年代使用標記-整理算法
//更加關注吞吐量
//串行收集器在新生代以及老年代的並行化
-XX:+UseParallelGC //新生代並行,老年代串行
-XX:+UseParallelOldGC //新生代並行,老年代並行
並行收集器其他參數
-XX:MaxGCPauseMills //最大停頓時間,單位毫秒,GC儘量保證回收時間不超過該時間
-XX:GCTimeRatio //0-100的取值範圍,垃圾回收時間佔總時間的比值,默認99,即允許1%時間做GC
//這兩個參數是矛盾的,吞吐量和停頓時間不可能同時調優
CMS收集器
-XX:UseConcMarkSweepGC //CMS收集器,與應用程序一起並行執行,減少停頓(儘可能縮小,不能完全消除),降低吞吐量
//Concurrent Mark Sweep 併發標記清除
//使用標記-清除算法
//與標記-整理相比,併發階段會降低吞吐量
//是老年代收集器(新生代使用PerNew)
//運行過程:
//初始標記【停頓】(標記根可直接關聯到的對象,速度快)
//併發標記【並行】(主要標記過程,標記全部對象)
//重新標記【停頓】(由於併發標記時,用戶線程依然運行,因此正式清理前再做修正)
//併發清除【並行】(基於標記結果,直接清理對象)
//併發重製【並行】(爲下次回收做準備)
//特點:
//儘可能降低停頓
//會影響系統整體吞吐量和性能
//清理不徹底(和用戶線程一起執行,會產生新的垃圾)
//不能再空間即將滿的時候再清理(如果預留空間不足,會引起concurrent mode failure,如果出現該錯誤,會使用[串行收集器]作爲後備)
-XX:CMSInitiatingOccupancyFraction //設置觸發GC的閾值,當堆空間佔用的比值達到該閾值即觸發
-XX:+UseCMSCompactAtFullCollection //full gc之後進行一次內存整理,整理期間停頓
-XX:CMSFullGCsBeforeCompaction //設置進行幾次full gc之後進行一次碎片整理
-XX:ParallelCMSThreads //設定CMS的線程數,一般情況約爲CPU數量
-XX:+CMSClassUnoladingEnabled //允許對類的元數據進行回收
-XX:CMSInitiatingPermOccupancyFraction //當永久區佔用率達到該百分比值時,啓用CMS收集器
-XX:UseCMSInitiatingOccupancyOnly //表示只在達到閾值的時候,才進行CMS回收
G1收集器
-XX:+UseG1GC //G1收集器
//G1(Garbage-First)是面向服務端應用的垃圾收集器。
//特點:
//並行與併發,G1收集器可以通過併發的方式讓Java程序繼續執行
//分代收集,G1可以不需要其他收集器配合就能獨立管理整個GC堆,採用不同的方式去處理新創建的對象和已經存活了一段時間、熬過多次GC的舊對象以獲取更好的收集效果。
//空間整合,G1從整體來看是基於 標記—整理算法 實現的收集器,從局部來看是基於 複製算法 實現的,這兩種算法都意味着G1運作期間不會產生內存空間碎片。
//可預測的停頓,降低停頓時間是G1和CMS共同的關注點,但G1除了追求低停頓外,還能建立可預測的停頓時間模型,能讓使用者明確指定在一個長度爲M毫秒的時間片段內,消耗在垃圾收集上的時間不得超過N毫秒。
//使用G1收集器時,Java堆的內存佈局就與其他收集器有很大差別,它將整個Java堆劃分爲多個大小相等的獨立區域(Region),雖然還保留有新生代和老年代的概念,但新生代和老年代不再是物理隔離的了,它們都是一部分Region(不需要連續)的集合。
-XX:G1HeapRegionSize //設置region的大小
//G1收集器之所以能建立可預測的停頓時間模型,是因爲它可以有計劃地避免在整個Java堆中進行全區域的垃圾收集。G1跟蹤各個Region裏面的垃圾堆積的價值大小(回收所獲得的空間大小以及回收所需時間的經驗值),在後臺維護一個優先列表,每次根據允許的收集時間,優先回收價值最大的Region(這也就是Garbage-First名稱的來由)。這種使用Region劃分內存空間以及有優先級的區域回收方式,保證了G1收集器在有限的時間內可以獲取儘可能高的收集效率。
//執行過程:
//初始標記【停頓】(標記根可以直接關聯到的對象,並修改TAMS[next top at mark start]的值),讓下一階段用戶程序併發執行時,能在正確的可用Region中創建新對象
//併發標記【並行】(標記所有對象,與用戶程序併發執行)
//最終標記【停頓】(修正在併發標記期間因用戶程序繼續運行而導致的標記變動)
//篩選回收【停頓】(對各個Region的回收價值和成本進行排序,根據用戶期望的停頓時間制定回收計劃,這個階段可以做到並行執行,但是隻回收一部分Regina,時間是用戶可控制的,停頓可以大幅提高收集效率)
-XX:InitiatingHeapOccupancyPercent //堆內存佔用達到該百分比值時啓動併發GC
-XX:MaxTenuringThreshold //提升老年代的最大臨界值,默認爲15
-XX:G1ReservePercent //預留多少內存,防止晉升失敗的情況,默認值是10
類加載器
class加載過程
加載-->鏈接(驗證,準備,解析)-->初始化
加載:讀取二進制文件,轉換爲方法區數據結構,在java堆生成對應的Class對象
鏈接:驗證–>驗證class文件格式(class文件以0xcafebabe開頭),版本號是否合理,驗證元數據(語法語義校驗),字節碼檢查,符號引用驗證(訪問方法的權限,屬性類是否存在等)
準備-->分配內存,併爲類設置初始值
解析-->將符號引用替換爲直接引用(符號替換爲真實內存地址)
初始化:執行類構造器(ClassInit),賦值static變量(final變量除外)和執行靜態代碼塊,子類初始化之前保證父類先初始化,ClassInit是線程安全的
ClassLoader
抽象類,負責類裝載過程中的加載階段,將java字節碼裝載到jvm中,可以定製,滿足不同的字節碼流獲取方式
重要方法:loadClass(載入並返回一個Class)、defineClass(定義一個類,不公開調用)、findClass(loadClass回調該方法,自定義時推薦重載該方法)、findLoadedClass(尋找已經加載的類)
幾種類加載器:啓動加載(Bootstrap ClassLoader)、擴展加載(Extension ClassLoader)、應用加載(App ClassLoader)、自定義加載(Custom ClassLoader)
除了Bootstrap外每個ClassLoader都有一個parents父類(雙親委派)
默認加載方式:自底向上檢查是否已加載(Bootstrap爲最上方),然後自頂向下加載類
-Xbootclasspath/a:D:/tmp/clz_dir
//指定bootstrap加載器的附加加載目錄
//上下文加載器,是一個角色,用以解決頂層ClassLoader無法訪問底層ClassLoader的類的問題,原理是在頂層ClassLoader中傳入底層ClassLoader的實例
Thread.setContextClassLoader()
雙親模式是默認的,但不是必須這麼做,如tomcat的WebAPPClassLoader就會先加載自己的class,找不到再委託parent,而不是先委託parent加載
性能監控工具
uptime(linux)
:系統運行時間,連接數,系統在1,5,15分鐘內的平均負載
top(linux)
:cpu,內存使用情況
vmstat(linux)
:統計cpu,內存,swap(上下文切換),io等情況
pidstat(linux)
:(需要安裝 sysstat)細緻觀察進程,監控cpu,io,mem,可以顯示進程中的線程信息(-t參數)
perfmon(win)
:windows性能監控工具
process Explorer(win)
:系統性能監控,查看線程運行情況
pslist(win cmd)
:(需要安裝)顯示java程序的運行情況
//java 自帶的監控工具
jdb java調試工具
jhat 分析java堆
jinfo 查看正在運行的java程序的參數,支持運行時修改部分參數,-flag <name>(打印指定jvm參數值)
jmap 生成java程序的堆快照和對象的統計信息,-histo,-dump
jps 列出java進程,-q(只輸出pid),-m(輸出主函數參數),-l(主函數完整路徑),-v(顯示傳遞給jvm的參數)
jrunscript 一個命令行腳本外殼
jstack 打印線程dump,-l(打印鎖信息),-m(打印java和native的幀信息),-F(強制dump,當jstack沒有響應時使用)
jstat 查看堆內存各部分的使用量,以及加載類的數量
jstatd 用於監控基於HotSpot的JVM中資源的創建及銷燬
jConsole 圖形化工具,查看java程序運行情況,監控堆信息,永久區使用情況,類加載情況等
jvisualvm 多合一的可視化監控工具,可以分析堆信息
jvm堆分析
內存溢出的原因
jvm內存中的內存區間:堆,永久區,線程棧,直接內存
堆溢出
:佔用大量堆空間,直接溢出(解決:增大堆空間或及時釋放內存)
永久區溢出
:大量的類信息導致(增大perm區,允許class回收)
棧溢出
:操作系統無法爲線程分配棧空間,即超過一定的線程數(每個線程獨立分配一塊空間),導致內存不足(解決:減少堆內存,減少線程棧大小)
直接內存溢出
:操作系統無法獲得足夠空間,外部內存超過系統可用內存(解決:減少堆內存,有意觸發gc)
MAT軟件(堆分析軟件)
eclipse下的軟件,可在eclipse官網下載
淺堆
:一個對象結構所佔用的內存大小,與對象內容無關,只與對象結構有關
深堆
:一個對象被gc回收後,可以真實釋放的內存大小,即可以通過對象訪問到的所有對象的淺堆之和
鎖
線程安全
使用鎖維護程序的串行訪問和安全性
對象頭mark
對象頭標記,32位
描述對象的hash,鎖信息,垃圾回收標記,年齡
偏向鎖
大部分情況是沒有競爭的,所以可以通過偏向來提高性能,鎖會偏向當前已經佔有鎖的線程,將對象頭的mark標記置爲偏向,並寫入線程id,只要沒有競爭,獲得偏向鎖的線程在將來進入同步塊時不需要做同步,當其他線程請求相同的鎖時,偏向模式結束,在競爭激烈的場合,偏向鎖會增加系統負擔
-XX:+UseBiasedLocking //1.6之後默認啓用
-XX:BiasedLockingStartupDelay //設置偏向鎖在程序啓動後的延遲時間,偏向鎖在系統啓動不會立馬啓用
輕量級鎖
BasicObjectLock
輕量級鎖是一種快速的鎖定方法,如果對象沒有被鎖定,將對象頭的mark指針保存到鎖對象中,將對象頭設置爲指向鎖的指針(在線程棧中),如果存在競爭,則升級爲重量級鎖
自旋鎖
當競爭存在時,如果線程可以很快獲得鎖,那麼可以不在系統層掛起線程,讓線程做幾個空操作,1.7之後爲默認啓用,如果同步塊很長,自旋失敗,會降低系統性能,如果同步塊很短,自旋成功,會節省系統切換時間
鎖的優化
減少鎖的持有時間
:縮小同步塊,儘量不同步整個方法
減小鎖粒度
:將大對象拆成小對象,如ConcurrentHashMap,將table分爲多個segment進行操作
鎖分離
:根據功能進行鎖分離,如讀寫鎖
鎖粗化
:對統一鎖多次請求,同步,釋放,可以將鎖放大化,增加鎖範圍
鎖消除
:如果發現不可能被共享的對象,則可以消除這些對象的鎖操作(-XX:+DoEscapeAnalysis(逃逸分析) -XX:+EliminateLocks(粗化鎖區域))
無鎖
:無鎖是樂觀的操作,再應用層面判斷多線程的干擾,如果有干擾,則重試,無鎖的實現(cas(比較交換指令)),如atomic包下的類
Class文件結構
語言無關性
各種jvm語言都可以編譯成class文件,運行在jvm上,並不是只有java語言,即java語言和jvm是兩個分離的部分
class文件結構
u1/u2/u4表示無符號整型以及佔用的字節數,文件結構如下
類型 | 名稱 | 數量 | 說明 |
---|---|---|---|
u4 | magic | 1 | 魔數 |
u2 | minor_version | 1 | 小版本 |
u2 | major_version | 1 | 大版本 |
u2 | const_pool_count | 1 | 常量數 |
cp_info | const_pool | const_pool_count-1 | 常量 |
u2 | access_flag | 1 | 訪問修飾符 |
u2 | this_class | 1 | 當前類,指向常量池的Class |
u2 | super_class | 1 | 父類,指向常量池的Class |
u2 | interface_count | 1 | 接口數量 |
u2 | interfaces | interface_count | 接口,指向常量池的Class |
u2 | field_count | 1 | 字段數量 |
field_info | fileds | field_count | 字段 |
u2 | method_count | 1 | 方法數量 |
method_info | methods | method_count | 方法 |
u2 | attr_count | 1 | 屬性數量 |
attr_info | attrs | attr_count | 屬性 |
魔數magic
:class文件魔數爲 0xCAFEBABE
minor.major
:java編譯版本
常量池
:支持的常用類型 (1)指向utf8的索引 (2)指向class的索引 (3)指向NameAndType的索引
描述 | 類型 | 結構 |
---|---|---|
utf-8編碼的Unicode字符串 | utf8 | tag 1,length u2,byte len |
int類型的字面值 | Integer | tag 3,byte u4 |
float類型的字面值 | Float | tag 4 |
long類型的字面值 | Long | tag 5 |
double類型的字面值 | Double | tag 6 |
對一個類或接口的符號引用 | Class | tag 7,name_index u2(1) |
string類型字面值的引用 | String | tag 8,string_index u2(1) |
對一個字段的符號引用 | Fieldref | tag 9,class_index u2(2),nameandtype_index u2(3) |
對一個類中方法的符號引用 | Methodref | tag 10,class_index u2(2),nameandtype_index u2(3) |
對一個接口中方法的符號引用 | InterfaceMethodref | tag 11,class_index u2(2),nameandtype_index u2(3) |
對一個字段或方法的部分符號引用 | NameAndType | tag 12,name_index u2(1),desc_index u2(1) |
類的標識符
:
標識 | value | 說明 |
---|---|---|
ACC_PUBLIC | 0x0001 | public |
ACC_FINAL | 0x0010 | final 不能被繼承 |
ACC_SUPER | 0x0020 | 是否允許使用invokespecial指令,1.2後爲true |
ACC_INTERFACE | 0x0200 | 是否爲接口 |
ACC_ABSTRACT | 0x0400 | 抽象類 |
ACC_SYNTHETIC | 0x1000 | 不是由用戶代碼生成,運行時生成,沒有源碼 |
ACC_ANNOTATION | 0x2000 | 是否爲註解 |
ACC_ENUM | 0x4000 | 是否是枚舉 |
字段標識符
:access_flag
標識 | value | 描述 |
---|---|---|
ACC_PUBLIC | 0x0001 | public |
ACC_PRIVATE | 0x0002 | private |
ACC_PROTECTED | 0x0004 | protected |
ACC_STATIC | 0x0008 | static |
ACC_FINAL | 0x0010 | final |
ACC_VOLATILE | 0x0040 | volatile |
ACC_TRANSIENT | 0x0080 | transient |
ACC_SYNTHETIC | 0x1000 | synthetic;沒有源碼,編譯器生成 |
ACC_ENUM | 0x4000 | enum枚舉類型 |
字段
:常量池引用,表示字段的名字 name_index u2,descriptor_index u2
標識 | 類型 |
---|---|
B | byte |
C | char |
D | double |
F | float |
I | int |
J | long |
S | short |
Z | boolean |
V | void |
L | 對象 – Ljava/lang/Object |
[ | 數組 – [Ljava/lang/String |
方法標識符
:指向常量池的索引,方法描述 (args)return 如: (I)V 爲 參數爲int返回值空,name_index u2,descriptor_index u2
標識 | value | 描述 |
---|---|---|
ACC_PUBLIC | 0x0001 | public |
ACC_PRIVATE | 0x0002 | private |
ACC_PROTECTED | 0x0004 | protected |
ACC_STATIC | 0x0008 | static |
ACC_FINAL | 0x0010 | final |
ACC_SYNCHRONIZED | 0x0020 | synchronized |
ACC_BRIDGE | 0x0040 | 編譯器產生,橋接方法 |
ACC_VARARGS | 0x0080 | 可變參數 |
ACC_NATIVE | 0x0100 | native |
ACC_ABSTRACT | 0x0400 | abstract |
ACC_STRICT | 0x0800 | strictfp |
ACC_SYNTHETIC | 0x1000 | 不在源碼中,編譯器生成 |
文件屬性
:在field和method中,可以有若干個attr,類文件也有attr用於描述一些額外的信息,attr本身也可以包含其他的attr
attribute_name_index u2 名字,指向常量池utf8
attribute_length u4 長度
info【attribute_length】 u1 內容
名稱 | 使用者 | 說明 |
---|---|---|
Deprecated | field method | 字段、方法、類被廢棄,attribute_length=0 |
ConstantValue | field | final常量,attribute_length=2,constantvalue_index u2指向常量池 |
Code | method | 方法的字節碼和其他數據 |
Exceptions | method | 方法的異常 |
LineNumberTable | Code_Attribute | 方法行號和字節碼映射 |
LocalVaribleTable | Code_Attribute | 方法局部變量表描述 |
SourceFile | Class file | 源文件名,attribute_length=2 |
Synthetic | field method | 編譯器產生的方法或字段 |
feild_info
–access_flags u2
–name_index u2
–descriptor_index u2
–attributes_count u2
–attribute_info attributes [attributes_count];
method_info
–access_flags u2
–name_index u2
–descriptor_index u2
–attributes_count u2
–attribute_info attributes [attributes_count];
sourceFile
–attribute_name_index u2
–attribute_length u4(固定爲2)
–soucefile_index u2(UTF-8常量索引)
exception
–attribute_name_index u2
–attribute_length u4
–number_of_exceptions u2
–exception_index_table [number_of_exceptions] u2(指向Constant_Class的索引)
LocalVariableTable
LocalVariableTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 local_variable_table_length;
{
u2 start_pc;
u2 length;
u2 name_index;
u2 descriptor_index;
u2 index;
} local_variable_table [local_variable_table_length];
}
LineNumberTable
LineNumberTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 line_number_table_length;
{
u2 start_pc;
u2 line_number;
} line_number_table [line_number_table_length];
}
code
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code [code_length];
u2 exception_table_length;
{
u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table [exception_table_length];
u2 attributes_count;
attribute_info attributes [attributes_count];
}
字節碼的執行
javap //JDK自帶的反彙編器
jit:just in time 將執行比較頻繁的代碼編譯成機器碼,-XX:CompileThreshold=100(設定jit閾值),-XX:+PrintCompilation(打印編譯信息)
其他說明
(1)dump:在特定時刻,將整個儲存裝置或儲存裝置之某部分的內容記錄在另一儲存裝置中
(2)新生代GC(Minor GC):指發生在新生代的垃圾收集動作,因爲Java對象大多都具備朝生夕滅的特性,所以Minor GC非常頻繁,一般回收速度也比較快
(3)老年代GC(Major GC / Full GC):指發生在老年代的GC,出現了Major GC,經常會伴隨至少一次的Minor GC(但非絕對的,在Parallel Scavenge收集器的收集策略裏就有直接進行Major GC的策略選擇過程)。Major GC的速度一般會比Minor GC慢10倍以上。
(4)吞吐量:吞吐量就是CPU用於運行用戶代碼的時間與CPU總消耗時間的比值,即吞吐量 = 運行用戶代碼時間 /(運行用戶代碼時間 + 垃圾收集時間)。
(5)Region:G1默認把堆內存分爲1024個分區,後續垃圾收集的單位都是以Region爲單位的。Region是實現G1算法的基礎,每個Region的大小相等,通過-XX:G1HeapRegionSize參數可以設置Region的大小。