摘要:前言本文內容基本摘抄自深入理解虛擬機,以供復習之用,沒有多少參考價值。此區域是唯一一個在虛擬機規范中沒有規定任何情況的區域。堆是所有線程共享的內存區域,在虛擬機啟動時創建。虛擬機上把方法區稱為永久代。
前言
本文內容基本摘抄自《深入理解Java虛擬機》,以供復習之用,沒有多少參考價值。想要更詳細了解請參考原書。
第二章 1.運行時數據區域程序計數器可以看作是當前線程所執行的字節碼的行號指示器,每條線程都需要有一個獨立的程序計數器。如果線程執行Java方法,計數器記錄正在執行的虛擬機字節碼指令地址;如果執行Native方法,計數器值為空。此區域是唯一一個在Java虛擬機規范中沒有規定任何OutOfMemoryError情況的區域。
Java虛擬機棧也是線程私有的,生命周期與線程相同。虛擬機棧描述的是Java方法執行的內存模型:每個方法在執行的同時都會創建一個棧幀用于存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。每一個方法從調用直至執行完成的過程,就對應著一個棧幀在虛擬機棧中入棧到出棧的過程。如果線程請求的棧深度大于虛擬機所允許的深度,將拋出StackOverflowError異常;如果虛擬機棧可以動態擴展,如果擴展時無法申請到足夠內存,就會拋出OutOfMemoryError異常。
本地方法棧類似虛擬機棧,區別是本地方法棧為虛擬機使用到的Native方法服務。
Java堆是所有線程共享的內存區域,在虛擬機啟動時創建。所有對象實例以及數組都要在堆上分配。Java堆是GC管理的主要區域。從內存回收角度,Java堆可以細分為新生代和老年代,如果使用復制算法收集,還可以分為Eden空間、From Survivor空間、To Survivor空間。從內存分配角度,線程共享的Java堆可能劃分出多個線程私有的分配緩沖區(TLAB)。如果堆中沒有內存完成實例分配,并且堆也無法再擴展時,將會拋出OutOfMemoryError異常。
方法區是所有線程共享區域,用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據。HotSpot虛擬機上把方法區稱為永久代。但用永久代實現方法區有問題,例如String.intern()在不同虛擬機有不同表現。JDK1.7已經把原本放在永久代的字符串常量池移出。當方法區無法滿足內存分配需求時,將拋出OutOfMemoryError異常。
運行時常量池是方法區的一部分。Class文件中除了類的版本、字段、方法、接口等描述信息外,還有常量池,這部分將在類加載后進入方法區的運行時常量池中存放。運行時常量池相對于Class文件常量池的另外一個特征是動態性,并非預置入Class文件中常量池的內容才能進入方法區運行時常量池,運行期間也可能將新的常量放入池中(intern())。
直接內存不是虛擬機運行時數據區一部分。JDK NIO引入了一種基于通道和緩沖區的I/O方式,它可以使用Native函數直接分配堆外內存,然后通過一個存儲在Java堆中的DirectByteBuffer對象作為這塊內存的引用進行操作。分配的直接內存導致各內存區域總和大于物理內存限制從而導致動態擴展時出現OutOfMenmoryError。
2.關于對象對象的創建:
對象的內存布局:
對象在內存中存儲的布局分為:對象頭、實例數據和對齊填充。對象頭分為對象運行時數據和類型指針。
對象運行時數據包括HashCode、GC分代年齡和鎖狀態標志位等。類型指針即對象指向它的類元數據的指針。另外,如果對象是一個Java數組,那在對象頭中還有一塊用于記錄數組長度的數據。
實例數據部分是對象真正存儲的有效信息,也是在程序代碼中所定義的各種類型的字段內容。
對齊補充不是必然存在,起著占位符作用。保證對象起始地址是8字節的整數倍。
對象的訪問:
Java程序通過棧上的reference數據來操作堆上的具體對象。訪問方式分為使用句柄和直接指針兩種。使用句柄,Java堆中會劃分出一塊內存作為句柄池,reference中存儲的就是對象的句柄地址,而句柄中包含了對象實例數據與類型數據各自的具體地址信息。如果使用直接指針訪問,那么Java堆對象的布局中就要放置訪問類型數據的相關信息。
3.部分虛擬機啟動參數
-Xms:堆的最小值
-Xmx:堆的最大值
-Xmn::堆分配給新生代的大小
-XX:+HeapDumpOnOutOfMemoryError:虛擬機出現內存溢出異常時Dump出當前內存堆轉儲快照
-Xss:棧容量
-XX:PermSize:永久代最小值
-XX:MaxPermSize:永久代最大值
-XX:MaxDirectMemorySize:本機直接內存大小,如果不指定,默認與-Xmx一樣。
1.對象存亡
判斷對象是否存活有兩種方法,引用計數算法和可達性分析。
引用計數算法:給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值加1;當引用失效時,計數器值減1;任何時刻計數器為0的對象就是不可能再被使用的。引用計數算法的優點是實現簡單,判定效率也高。缺點是它很難解決對象之間相互循環引用的問題。
可達性分析算法:通過一系列的稱為“GC Roots”的對象作為起始點,從這些節點開始向下搜索,搜索所走過的路徑稱為引用鏈,當一個對象到GC Roots沒有任何引用鏈相連時,則證明此對象是不可用的。可作為GC Roots的對象包括:虛擬機棧中引用的對象、方法區中類靜態屬性引用的對象、方法區中常量引用的對象、本地方法棧中JNI引用的對象。
對象引用:
強引用(Strong Reference)、軟引用(Soft Reference)、弱引用(Weak Reference)、虛引用(Phantom Reference)。
強引用只要存在,垃圾收集器永遠不會回收被引用對象。軟引用用來描述還有用但并非必須的對象。對于軟引用關聯著的對象,在系統將要發生內存溢出異常之前,將會把這些對象列進回收范圍進行二次回收。弱引用也用來描述非必須對象,被弱引用關聯的對象只能生存到下一次垃圾收集發生之前。一個對象是否有虛引用的存在不影響生存時間,也無法通過虛引用取得對象實例。虛引用唯一目的是在垃圾回收時收到一個系統通知。
對象存亡:
宣告對象死亡至少要經歷兩次標記過程:如果對象在進行可達性分析后發現沒有與GC Roots相連接的引用鏈,那它將會被第一次標記并進行一次篩選是否有必要執行finalize()方法。若對象沒有覆蓋此方法或曾經調用過此方法,則沒必要執行。如果在finalize()方法中重新與引用鏈建立聯系,則對象存活,否則 進行第二次標記。
方法區的回收:
永久代回收包括廢棄常量和無用的類。其中類的回收條件較為苛刻:該類所有實例已回收;該類的類加載器已回收;該類的Class對象沒有被引用。滿足這三個條件才可以回收,而不是必然回收。
2.垃圾收集算法
標記-清除算法:標記和清除效率都不高且標記清除后產生大量不連續內存碎片。
復制算法:堆分為一塊Eden和兩塊Survivor,大小為8:1:1,每次使用Eden和其中一塊Survivor,回收時,將上面存活的對象復制到另外一塊Survivor上,清理Eden和剛才使用過的Survivor空間。當Survivor空間不夠時,需要依賴老年代進行分配擔保。
標記-整理算法:復制算法在對象存活率高時需要較多復制操作,效率較低。標記整理類似標記清除,不過標記后讓所有存活對象移向一端,然后清理掉邊界以外的內存。
分代收集算法:根據對象存活周期不同將內存劃分為幾塊。新生代使用復制算法,老年代使用標記清除和標記整理。
3.算法實現
可達性分析時間敏感:
可達性分析從GC Roots中查找引用鏈,GC Roots節點包括全局性引用與執行上下文,而僅僅方法區就有數百兆,如果逐個檢查,會耗費大量時間。可達性分析還需要GC Roots停頓。
安全點:
HotSpot使用一組OopMap的數據結構存放對象引用。但HotSpot沒有為每條指令生成OopMap,只在安全點記錄信息。一般“長時間執行”的指令,如方法調用、循環跳轉、異常跳轉會產生SafePoint。GC時讓所有線程在最近安全點停頓分為搶先式中斷和主動式中斷。
安全區域:
線程處于Sleep或Blocked狀態,無法響應JVM的中斷請求,就無法執行到安全點掛起。安全區域是指一段代碼之中,引用關系不會發生變化,這個區域任意地方開始GC都是安全的。
4.垃圾收集器
Serial收集器:
單線程收集器,不僅僅只會使用一個CPU或一條收集線程去完成垃圾收集工作,它在進行垃圾收集時必須暫停所有其他工作線程。優點是簡單而高效。
ParNew收集器:
多線程收集器,除了多線程收集都與Serial一樣。優點是除了Serial,只有它能與CMS配合工作。
Parallel Scavenge收集器:
多線程收集器,目標是吞吐量優先(CPU用于運行用戶代碼的時間與CPU總消耗時間的比值)。
Serial Old收集器:
Serial老年代版本,單線程收集器,“標記-整理”算法。
Parallel Old收集器:
Parallel Scavenge的老年代版本,多線程收集,“標記-整理”算法,注重吞吐量。
CMS收集器:
以獲取最短回收停頓時間為目標的收集器。“標記-清除”算法,分為:初始標記、并發標記、重新標記、并發清除。初始標記和重新標記仍然需要“Stop The World”。
初始標記僅僅標記GC Roots能直接關聯到的對象,速度很快;并發標記就是進行GC Roots Tracing的過程;重新標記是為了修正并發標記期間因用戶程序繼續運作而導致標記產生變動的那一部分對象的標記記錄,時間比初始標記稍長,比并發標記短。由于整個過程耗時最長的并發標記和并發清除過程收集器線程都可以與用戶線程一起工作。所以CMS的內存回收是與用戶線程一起“并發”執行的。
CMS有3個缺點:對CPU資源非常敏感;無法處理浮動垃圾、會產生大量空間碎片(標記-清除)。
G1收集器:
G1的優點是并行與并發、分代收集、空間整合、可預測的停頓。回收過程分為:初始標記、并發標記、最終標記、篩選回收。
5.內存分配與回收策略
對象優先在Eden分配
大對象直接進入老年代
長期存活的對象將進入老年代
動態對象年齡判定
空間分配擔保
第四章1.JDK命令行工具
jps:虛擬機進程狀況工具。可以列出正在運行的虛擬機進程,并顯示虛擬機執行主類名稱以及這些進程的本地虛擬機唯一ID。
jstat:虛擬機統計信息監視工具。可以顯示本地或者遠程虛擬機進程中的類裝載、內存、垃圾收集、JIT編譯等運行數據。
jinfo:Java配置信息工具。可以實時地查看和調整虛擬機各項參數。
jmap:java內存映像工具。用于生成堆轉儲快照。
jhat:虛擬機堆轉儲快照分析工具。分析jmap生成的快照。
jstack:Java堆棧跟蹤工具。用于生成虛擬機當時的線程快照,就是當前虛擬機內每一條線程正在執行的方法堆棧的集合。
HSDIS:JIT生成代碼反匯編。
2.JDK可視化工具
jconsole:Java監視與管理控制臺。
VisualVM:多合一故障處理工具。
1.Class類文件的結構
Class文件格式采用一種類似于C語言結構體的偽結構來存儲數據,這種偽結構只有兩種數據類型:無符號數和表。無符號數分為u1、u2、u4、u8。表由多個無符號數或者其他表作為數據項構成的復合數據類型。
魔數
Class文件版本
訪問標志
類索引、父類索引與接口索引集合
字段表集合
方法表集合
屬性表集合
其中,屬性表集合有Code屬性、Exceptions屬性、LineNumberTable屬性、LocalVariableTable屬性、SourceFile屬性、ConstantValue屬性、InnerClasses屬性、Deprecated及Synthetic屬性、stackMapTable屬性、Signature屬性、BootstrapMethods屬性等。
2.字節碼指令
加載和存儲指令
運算指令
類型轉換指令
對象創建與訪問指令
操作數棧管理指令
控制轉移指令
方法調用和返回指令
異常處理指令
同步指令
第七章1.類加載機制
虛擬機把描述類的數據從Class文件加載到內存,并對數據進行校驗、轉換解析和初始化,最終形成可以被虛擬機直接使用的Java類型,這就是虛擬機的類加載機制。Java語言里,類型加載、連接和初始化過程都是在程序運行期間完成的,因此Java有高度的靈活性。
2.類加載的時機
加載、驗證、準備、初始化、卸載按部就班的開始,解析階段可以在初始化之后開始(為了支持Java語言的運行時綁定)。
立即對類進行初始化的五種情況:
遇到new(實例化對象)、getstatic(讀取類的靜態字段)、putstatic(設置類的靜態字段)、invokestatic(調用一個類的靜態方法)4條字節碼指令時;
使用reflect對類反射調用時
初始化一個類時,如果其父類還未初始化(對于接口來說,只有在真正使用父接口時才會初始化)
虛擬機啟動時指定執行主類
使用動態語言支持時,MethodHandle的解析結果的方法句柄所對應的類沒有進行過初始化
通過子類引用父類的靜態字段,不會導致子類初始化;通過數組定義來引用類,不會觸發此類的初始化;常量在編譯階段會存入調用類的常量池中,本質上并沒有直接引用到定義常量的類,因此不會觸發定義常量的初始化。
3.類加載的過程
加載:
通過一個類的全限定名來獲取定義此類的二進制字節流;
將這個字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構;
在內存中生成一個代表這個類的java.lang.Class對象,作為方法區這個類的各種數據的訪問入口(存放在方法區);
驗證:
文件格式驗證
元數據驗證
字節碼驗證
符號引用驗證
準備:
準備階段是正式為類變量分配內存并設置類變量初始值(通常情況為零值,final則直接賦值)的階段,這些變量所使用的內存都將在方法區中進行分配。
解析:
解析階段是虛擬機將常量池內的符號引用替換為直接引用的過程。符號引用以一組符號來描述所引用的目標,符號可以是任何形式的字面量,符號引用與虛擬機實現的內存布局無關;直接引用可以是直接指向目標的指針、相對偏移量或是一個能間接定位到目標的句柄,直接引用和虛擬機實現的內存布局相關。
類或接口的解析
字段解析
類方法解析
接口方法解析
方法類型解析
方法句柄解析
調用點限定符解析
初始化:
前面的類加載過程中,除了加載階段用戶應用程序可以通過自定義類加載器參與之外,其余動作完全由虛擬機主導和控制。到了初始化階段,才真正開始執行類中定義的Java程序代碼(字節碼)。初始化階段是執行類構造器
4.類加載器
類加載階段中的“通過一個類的全限定名來獲取描述此類的二進制字節流”就是由類加載器實現的。且類加載器左右不限于此,任意一個類都需要由加載它的類加載器和這個類本身一同確立其在Java虛擬機中的唯一性,每一個類加載器都擁有一個獨立的類名稱空間。
雙親委派模型:
從JVM角度只存在兩種類加載器:啟動類加載器(Bootstrap ClassLoader),由C++實現;所有其他類加載器,由Java實現。從開發角度分為四類:啟動類加載器(Bootstrap ClassLoader),
雙親委派模型的工作過程是:如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,所有的加載請求最后都應該傳送到頂層的啟動類加載器,只有當父加載器反饋無法加載(搜索范圍沒找到需要的類)時,子加載器才會嘗試自己去加載。
雙親委派模型的好處是Java類隨著它的類加載器一起具備了一種帶有優先級的層次關系,保證了Java程序的穩定運作。
破壞雙親委派模型:
面對已經存在的用戶自定義類加載器的實現代碼,為了向前兼容,JDK1.2之后的java.lang.ClassLoader添加了一個新的protected方法findClass()。
雙親委派模型很好地解決了各個類加載器的基礎類的統一問題,但基礎類可能會回調用戶代碼。因此引入線程上下文類加載器,可以通過java.lang.Thread類的setContextClassLoader()方法進行設置,默認為應用程序類加載器。這其實是父類加載器請求子類加載器完成類加載,打破了雙親委派模型。
用戶對程序動態性的追求導致破壞(代碼熱替換、模塊熱部署)。OSGI實現模塊化部署的關鍵是它自定義的類加載器機制的實現。每一個程序模塊(Bundle)都有一個自己的類加載器,當需要更換一個Bundle時,就把Bundle連同類加載器一起換掉以實現代碼的熱替換。
第八章1.運行時棧幀結構
棧幀存儲了方法的局部變量表、操作數棧、動態鏈接和方法返回地址等信息。每一個方法從調用開始至執行完成的過程,都對應著一個棧幀在虛擬機棧里面從入棧到出棧的過程。
局部變量表:
局部變量表是一組變量值存儲空間,用于存放方法參數和方法內部定義的局部變量。在Java程序編譯為Class文件時,就在方法的Code屬性的max_locals數據項中確定了該方法需要分配的局部變量表的最大容量。
虛擬機通過索引定位的方式使用局部變量表,索引值的范圍是從0開始至局部變量表最大的Slot數量。如果執行的是實例方法,局部變量表中第0位索引的Slot默認是用于傳遞方法所屬對象實例的引用,可通過“this”訪問。
存在一種特殊情形,對象占用內存大、此方法的的棧幀長時間不回收、方法調用次數達不到JIT編譯條件,手動將不再使用的變量設置null是有用的。
局部變量不像類變量有準備階段,沒有賦初始值不能使用。
操作數棧:
操作數棧是一個后入先出棧。同局部變量表一樣,操作數棧的最大深度也在編譯的時候寫入到Code屬性的max_stack數據項中。
當一個方法剛剛開始執行時,這個方法的操作數棧是空的,在方法的執行過程中,會有各種字節碼指令往操作數棧中寫入和提取內容,也就是入棧出棧操作。
概念模型中,兩個棧幀作為虛擬機棧的元素,是完全相互獨立的。但在大多數虛擬機的實現里都會做一些優化處理,令兩個棧幀出現一部分重疊。
動態鏈接:
Class文件的常量池中存有大量的符號引用,這些符號引用一部分會在類加載階段或者第一次使用時轉化為直接引用,這種轉化稱為靜態解析;另外一部分將在每一次運行期間轉化為直接引用,稱為動態鏈接。
方法返回地址:
方法開始執行后,有兩種退出方式:正常完成出口和異常完成出口。方法返回時需要在棧幀中保存一些信息,用來幫助恢復它的上層方法的執行狀態。方法正常退出時,調用者的PC計數器的值可以作為返回地址,會在棧幀中保存;方法異常退出時,返回地址是要通過異常處理器表來確定,棧幀中不保存。
附加信息:
允許增加附加信息到棧幀中。
2.方法調用
方法調用階段唯一的任務就是確定被調用方法的版本,暫不涉及方法內部運行。
Class文件的編譯過程中不包含傳統編譯中的連接步驟,一切方法調用在Class文件里面存儲的都只是符號引用,而不是方法在內存的入口地址。需要在類加載期間,甚至到運行期間才能確定目標方法的直接引用。
Java虛擬機五條方法調用指令:
invokestatic:調用靜態方法;
invokespecial:調用實例構造器
invokevirtual:調用所有的虛方法。
invokeinterface:調用接口方法,會在運行時再確定一個實現此接口的對象。
invokedynamic:現在運行時動態解析出調用點限定符所引用的方法,然后再執行該方法。
前4條調用指令分派邏輯是固化在Java虛擬機內部的,而invokeddynamic指令的分派邏輯是由用戶所設定的引導方法決定的。
解析:
在類加載的解析階段,會將其中的一部分符號引用轉化為直接引用,這部分調用目標在程序代碼寫好、編譯器進行編譯時就必須確定下來。這類方法的調用稱為解析。
只要能被invokestatic和invokespecial指令調用的方法,都可以在解析階段中確定唯一的調用版本,在類加載的時候就會把符號引用解析為該方法的直接引用。
Java中的非虛方法除了使用invokestatic、invokespecial調用的方法之外,還有final修飾的方法,雖然final使用invokevirtual調用。
分派:
解析調用一定是靜態過程,在編譯期間完全確定,在類加載的解析階段就會把符號引用替換為直接引用;而分派調用可能是靜態或動態。
靜態分派:所有依賴靜態類型來定位方法執行版本的分派動作稱為靜態分派。靜態分派的典型應用是方法重載。靜態分派發生在編譯階段,因此確定靜態分派的動作實際上不是由虛擬機來執行的。另外,編譯器雖然能確定出方法的重載版本,但有時并不唯一,原因是字面量不需要定義,所以字面量沒有顯式的靜態類型。
動態分派:運行期間根據實際類型確定方法執行版本的分派過程稱為動態分派。動態分派的典型應用是方法重寫。invokevirtual指令執行的第一步就是在運行期確定接收者的實際類型。
單分派與多分派:方法的接收者與方法的參數統稱為方法的宗量,根據分派基于多少宗量,可以將分派劃分為單分派和多分派。Java語言是一門靜態多分派、動態單分派的語言。
虛擬機動態分派實現:使用虛方法表索引來代替元數據查找以提高性能。虛方法表中存放著各個方法的實際入口地址。
3.動態類型語言支持
動態類型語言的關鍵特征是它的類型檢查的主體過程是在運行期而不是編譯期。編譯器就進行類型檢查過程的語言就是最常用的靜態類型語言。“變量無類型而變量值才有類型”也是動態類型語言的一個重要特征。
靜態語言在編譯期確定類型,最顯著的好處是編譯器可以提供嚴謹的類型檢查;動態類型語言在運行期確定類型,可以提供更大的安全性,也使代碼更加清晰和簡潔。
java.lang.invoke:
這個包的主要目的是在之前JVM單純依靠符號引用來確定調用的目標方法這種方式之外,提供一種新的動態確定目標方法的機制,稱為MethodHandle。
MethodHandle與Reflection相似之處很多,區別如下:Reflection是在模擬Java代碼層次的方法調用,MethodHand是在模擬字節碼層次的調用;Reflection是重量級,MethodHandle是輕量級;由于MethodHandle是對字節碼的模擬,所以虛擬機在這方面的優化可以被MethodHandle借鑒。
invokedynamic:
invokedynamic指令與MethodHandle機制的作用一樣,解決原有4條“invoke*”指令方法分派規則固化在虛擬機之中的問題,把如何查找目標方法的決定權從虛擬機轉嫁到具體用戶代碼之中。區別是一個采用上層Java代碼和API實現,另一個用字節碼和Class中其他屬性、常量來完成。
4.基于棧的字節碼解釋執行引擎
Java語言中,Javac編譯器完成了程序代碼經過詞法分析、語法分析到抽象語法樹,再遍歷語法樹生成線性的字節碼指令流的過程。這一部分在JVM之外進行,而解釋器和解釋執行在JVM內部,所以Java的編譯是半獨立的實現。
Java編譯器輸出的指令流,是一種基于棧的指令集架構。基于棧的指令集主要優點就是可移植,缺點是執行速度相對較慢。
第十章Javac編譯器
從Javac的代碼來看,編譯過程分為3個過程:
解析與填充符號表過程:詞法、語法分析;填充符號表
插入式注解處理器的注解處理過程
語義分析與字節碼生成過程:標注檢查、數據及控制流分析、解語法糖、字節碼生成
Java語法糖
泛型和類型擦除:泛型的本質是參數化類型,即所操作的數據類型被指定為一個參數。Java語言中的泛型只在程序源碼中存在,在編譯后的字節碼文件中,就已經替換為原來的原生類型,并在相應地方插入了強制類型轉化代碼,ArrayList
自動裝箱、拆箱與循環遍歷:Java語言使用最多的語法糖。
條件編譯:根據布爾常量值的真假,編譯器將會把分支中不成立的代碼塊消除掉,由于這種條件編譯的實現方式使用了if語句,所以只能寫在方法體內部,只能實現語句基本塊級別的條件編譯。
第十一章1.HotSpot虛擬機內的即時編譯器
解釋器與執行器:
當程序需要迅速啟動和執行的時候,解釋器可以首先發揮作用,省去編譯的時間,立即執行。在程序運行后,隨著時間的推移,編譯器逐漸發揮作用,把越來越多的代碼編譯成本地代碼之后,可以獲取更高的執行效率。
HotSpot虛擬機內置兩個即時編譯器,分別稱為Client Compiler和Server Compiler(C1和C2).目前主流的HotSpot虛擬機中,默認采用解釋器與其中一個編譯器直接配合的方式工作。為了在程序啟動響應速度與運行效率之間達到最佳平衡,HotSpot虛擬機會逐漸啟用分層編譯的策略。
編譯對象與觸發條件:
在運行過程中會被即時編譯器編譯的熱點代碼有兩類:被多次調用的方法;被多次執行的循環體。這兩種情況編譯器都會以整個方法作為編譯對象。
判斷是否是熱點代碼和是否需要觸發即時編譯的行為稱為熱點探測,方式分為:基于采樣的熱點探測、基于計數的熱點探測。
編譯過程:
Server Complier和Client Complier兩個編譯器編譯過程不一樣。Client是一個簡單快速的三段式編譯器,主要關注局部性的優化,Server是一個充分優化過的高級編譯器。
2.編譯優化技術
方法內聯:去除方法調用的成本(建立棧幀等);可以便于在更大范圍內采取后續的優化手段。
冗余訪問消除:
復寫傳播
無用代碼消除
公共子表達式消除:如果表達式E已計算過,且E中所有變量值未發生變化,那就直接用已計算過的代替
數組范圍檢查消除:如果編譯器只要通過數據流分析就可以判定循環變量的取值范圍在區間內,那在整個循環中可以把數組的上下界檢查消除,可以節省很多次的條件判斷操作
逃逸分析:分析對象動態作用域:當一個對象在方法中被定義后,它可能被外部方法所引用,例如作為調用參數傳遞到方法中,稱為方法逃逸,還有可能被外部線程訪問到,稱為線程逃逸。如果確認無法逃逸,可以進行一些高效優化:棧上分配、同步消除、標量替換。
第十二章1.Java內存模型
Java內存模型規定了所有的變量都存儲在主內存中(虛擬機內存一部分)。每條線程還有自己的工作內存,線程的工作內存中保存了該線程使用到的變量的主內存的副本拷貝,線程對變量的所有操作都必須在工作內存中進行,而不能直接讀寫主內存中的變量。不同的線程之間也無法直接訪問對方工作內存中的變量,線程變量值的傳遞均需要通過主內存來完成。
內存交互:lock、unlock、read、load、use、assign、store、write。
volatile:
volatile變量兩種特性:第一是保證此變量對所有線程的可見性,可見性是指當一條線程修改了這個變量的值,新值對于其他線程立即可知。第二是禁止指令重排序優化。
volatile使用場景:運算結果并不依賴變量的當前值,或者能夠確保只有單一的線程修改變量的值;變量不需要與其他的狀態變量共同參與不變約束。
原子性、可見性、有序性
先行發生原則:先行發生是Java內存模型中定義的兩項操作之間的偏序關系,如果說操作A先行發生于操作B,其實就是在發生操作B之前,操作A產生的影響能被操作B觀察到:程序次序規則、監視器鎖規則、volatile變量規則。時間先后順序與先行發生原則之間基本沒有太大關系。
2.Java與線程
實現線程主要有3種方式:使用內核線程實現、使用用戶線程實現和使用用戶線程加輕量級進程混合實現。Java采用一對一線程模型。
Java線程調度:線程調度是指系統為線程分配處理器使用權的過程,分別是協同式線程調度和搶占式線程調度。
線程狀態:新建、運行、無限期等待、限期等待、阻塞、結束。
第十三章1.線程安全
Java中各種操作共享的數據分為以下5類:不可變、絕對線程安全、相對線程安全、線程兼容、線程對立。
線程安全的實現方法:互斥同步、非阻塞同步、無同步方案。
2.鎖優化
自旋鎖和自適應自旋、鎖消除、鎖粗化、輕量級鎖、偏向鎖。
第五章、第九章、第十章的插入式注解處理器等實例分析需要重點看一下。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68707.html
摘要:抽時間重新讀了一遍深入理解一書。驗證確保文件的字節流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全。可見性可見性是指當一個線程修改了共享變量的值,其他線程能夠立即得知這個修改。 抽時間重新讀了一遍《深入理解JVM》一書。以下為摘錄內容。 1 java內存區域 showImg(https://segmentfault.com/img/bVboDgk?w=617&h=365...
摘要:年開始工作,年畢業,兩年來的工作接觸知識面很廣,用的東西比較多,包括基礎的開發到開發到大數據,推薦系統,到服務器運維,到數據庫維護,,,可愈發明白貪多嚼不爛的道理,唯有才能踏踏實實,趁著剛剛讀完這本書,想復習,順便寫一些筆記,聊以鞏固。 13年開始工作,14年畢業,兩年來的工作接觸知識面很廣,用的東西比較多,包括基礎的java開發到j2ee,web開發,到大數據,推薦系統,到服務器運維...
摘要:監控和故障處理工具顯示指定系統內所有的虛擬機進程用于收集虛擬機各方面的運行數據。的常用功能選項測試上面輸出了我正在運行程序的包名下的類名虛擬機統計信息監視工具使用于監視虛擬機各種運行狀態信息的命令行工具。 《深入理解Java虛擬機:JVM高級特性與最佳實踐(第二版》讀書筆記與常見面試題總結 本節常見面試題(推薦帶著問題閱讀,問題答案在文中都有提到): JVM調優的常見命令行工具有哪些?...
閱讀 812·2021-11-18 10:02
閱讀 2503·2021-11-11 16:54
閱讀 2749·2021-09-02 09:45
閱讀 653·2019-08-30 12:52
閱讀 2774·2019-08-29 14:04
閱讀 2745·2019-08-29 12:39
閱讀 447·2019-08-29 12:27
閱讀 1887·2019-08-26 13:23