【讀過的書,留下的跡】深入理解Java虛擬機器__Java

來源:互聯網
上載者:User
前言

  最近發現有時候看完一本書,時間久了容易忘記,看書不總結思考效果大打折扣,故打算寫這一系列文章,一是為了整理書中的要點,協助自己消化理解;二是勉勵自己多看書思考。文章中不會把書中內容講解的非常詳細,只是總結概括,適合已經閱讀過該書的讀者。 第2章:Java記憶體地區與記憶體溢出異常

(1)JVM運行時資料區



程式計數器
當前線程所執行的位元組碼的行號指標 Java虛擬機器棧
線程私人 基礎資料類型,參考型別 本地方法棧
與Java虛擬機器棧類似 前者為執行Java方法(位元組碼)服務,後者為Native方法服務 Java堆
所有對象執行個體以及數組分配

方法區 載入的類資訊、常量、靜態變數、即時編譯後的代碼等資料 運行時常量池

特殊:直接記憶體 NIO類,可直接分配堆外記憶體DirectByteBuffer,受本機總記憶體限制

(2)OutOfMemoryError異常 Java堆溢出
無限new對象 虛擬機器棧、本地方法棧溢出
無限遞迴函式、無限建立線程 方法區、運行時常量池溢出
無限產生String使常量池溢出 產生大量類使方法區溢出(利用反射等) 直接記憶體溢出
填充DirectByteBuffer 第3章:垃圾收集器與記憶體配置策略

(1)判斷對象存活 引用計數演算法 可達性分析演算法
實現:GC Root:虛擬機器棧中所引用的對象、方法區中類靜態屬性引用的對象、方法區中常量引用。虛擬機器可直接得知哪些地方存放著對象引用,如在HotSpot虛擬機器中使用OopMap的資料結構實現。 強引用:永遠不會回收 軟引用:記憶體溢出前回收 弱引用:下一次GC被回收 虛引用

(2)垃圾收集演算法 標記-清楚演算法
簡單,效率不高,產生片段 複製演算法
效率較高,浪費空間 標記-整理演算法
沒有片段 分代收集演算法
新生代,老年代

(3)垃圾收集器



Serial收集器
單線程,簡單而高效,開始收集時停止所有背景工作執行緒(Stop The World) 適用於Client模式下的虛擬機器 ParNew收集器
Serial的多線程版,Stop The World, 只有Serial和ParNew能與CMS配合使用 Server模式下的虛擬機器首選新生代收集器 Parallel Scavenge收集器
基於最佳化輸送量,上述兩者是基於最佳化停頓時間 適合在後台運算而不需要太多互動的任務 Serial Old收集器
在於給Client模式下的虛擬機器用 Parallel Old收集器
配合Parallel Scavenge使用,“輸送量優先”收集器 CMS收集器
CMS(Concurrent Mark Sweep)收集器是一種以獲得最短回收停頓時間為目標的收集器 優點:並發收集、低停頓 缺點:消耗CPU,無法處理浮動垃圾,基於標記清楚觸發記憶體整理時無法並發 G1收集器
特點:並行並發、分代收集、空間整合、可預測停頓

(4)記憶體配置 優先在新生代Eden區中分配 大對象直接進入老年代 長期存活的對象將進入老年代(對象Age計數器) 動態對象年齡判定 第6章:類檔案結構

(1)系統無關性 實現程式設計語言與作業系統的無關性的基礎是虛擬機器和位元組碼儲存格式,Java虛擬機器不和包括Java在內的任何語言綁定,它只與“Class檔案”這種特定的二進位檔案格式關聯
程式設計語言->編譯器->位元組碼(.class檔案)->虛擬機器

(2)Class檔案結構 任何一個Class檔案都對應著唯一一個類或介面的定義資訊,但類或介面並不一定定義在Class檔案中,也可通過類載入器直接產生等 Class檔案包含有代碼以及支援代碼用的中繼資料(metadata)
代碼部分就是位元組碼 中繼資料部分則包括諸如類名、成員名、方法簽名、常量池、方法大小、方法的求值棧佔用量等許多資訊 Class檔案格式包括魔數、常量池、訪問標誌、類索引、父類索引、介面索引、欄位集合、方法集合等

第7章:虛擬機器類載入機制

(1)名詞 虛擬機器類載入機制(簡稱類載入)
虛擬機器把描述類的資料從Class檔案載入到記憶體,並對資料進行校正、轉換解析和初始化,最終形成可以被虛擬機器直接使用的Java類型 載入
類載入過程中的一步 類載入器



(2)類載入的時機 虛擬機器規範沒強制要求載入的時機,但是嚴格規定了有且只有5種情況必須立即對類進行初始化
遇到new,getstatic,putstatic,invokestatic這4條位元組碼指令,常見的即使用new關鍵字、讀取或設定一個類的靜態欄位(被final修飾的除外) 使用java.lang.reflect包的方法對類進行反射調用時 初始化一個類,但其父類未初始化時 虛擬機器啟動時,使用者需要指定一個要執行的主類 當使用JDK1.7的動態語言支援時….(少用)

(3)類載入過程 載入
虛擬機器需要完成3件事
1.通過一個類的全限定名來擷取定義此類的二進位位元組流 2.將這個位元組流所代表的靜態儲存結構轉化為方法區的運行時資料結構 3.在記憶體中產生一個代表這個類的java.lang.Class對象,作為方法區這個類的各種資料的訪問入口 載入階段完成後,虛擬機器外部的二進位位元組流就按虛擬機器所需的格式儲存在方法區之中,方法區中的資料存放區格式由虛擬機器實現自行定義 驗證
目的:確保Class檔案的位元組流中包含的資訊符合當前虛擬機器的要求,並且不會危害虛擬機器自身的安全 包含:
檔案格式驗證:只有通過這個階段,位元組流才會進入記憶體的方法區中進行儲存,所以後面的3個驗證階段全部基於方法區的儲存結構進行,不再直接操作位元組流 中繼資料驗證 位元組碼驗證 符號引用驗證 準備
正式為類變數分配記憶體,並設定類變數初始值的階段,這些變數所使用的記憶體都將在方法區中進行分配 注意。
1:進行記憶體配置的僅包括類變數(被static修飾的變數),而不包括執行個體變數,執行個體變數在對象執行個體化時在Java堆中分配 2:初始值指資料類型的零值,實際賦值在初始化階段 解析
將常量池內的符號引用替換為直接引用的過程 初始化
到了初始化,才真正執行類中定義的Java程式碼(即位元組碼)

(4)類載入器

定義:類載入階段中“通過一個類的全限定名來擷取定義此類的二進位位元組流”這個動作在Java虛擬機器外實現,實現這個動作的代碼稱為“類載入器”

判斷類是否相等 1:是否由同一個載入器載入 2:這個類本身是否相等

3種系統提供的Java程式類載入器 1:啟動類載入器:負責將\lib下的類庫載入到虛擬機器記憶體中 2:擴充類載入器:負責載入\lib\ext下的類庫 3:應用程式類載入器:使用者路徑上的類庫載入

雙親委派模型:除了頂層的啟動類載入器外,其餘的類載入器都有自己的父類載入器 工作過程:一個類載入器收到類載入請求時,首先把請求委派給父類載入器去完成,只有父類載入器反饋無法完成,子載入器才嘗試載入 好處:Java類隨著它的類載入器一起具備有優先順序的層次關係,詳見“判斷類是否相等” 第8章:虛擬機器位元組碼執行引擎

所有的Java虛擬機器的執行引擎都是一致的:輸入的是位元組碼檔案,處理過程是位元組碼解析的等效過程,輸出的是執行結果

許多Java虛擬機器的執行引擎在執行Java代碼的時候有解釋執行(通過解譯器執行)和編譯執行(通過即時編譯器產生本地代碼執行) 第10章:早期(編譯期)最佳化

(1)概述 前端編譯器:Javac
把.java檔案轉變成.class檔案的過程 JIT編譯器:HotSpot VM的C1,C2編譯器
即時編譯器,把位元組碼轉變成機器碼的過程

(2)前端編譯器 編譯過程大致分為3個過程 1:解析與填充符號表過程
詞法分析、文法分析等 2:插入式註解處理器的註解處理過程 3:分析與位元組碼產生過程
文法糖解析,位元組碼產生

(3)文法糖 範型與類型擦除
C#的範型仔系統運行期間產生,有自己的虛方法表和類型資料,即類型膨脹,是真實範型 Java語言的範型是基於類型擦除,即編譯過程中轉為原生類型,並響應地方插入強制轉換,偽範型 第11章:晚期(運行期)最佳化

即時編譯器:為了提高熱點代碼執行效率,在運行時,虛擬機器將會把這些代碼編譯成與本地平台相關的機器碼

(1)優缺點 解譯器
迅速啟動,執行快,節約記憶體 編譯器
時間推移,發揮作用,提升執行效率

(2)判斷熱點代碼 被多次調用的方法
基於採樣的熱點探測:周期性檢查各個線程的棧頂,統計哪個方法出現頻率高 基於計數器的熱點探測:方法調用計數器 被多次執行的迴圈體
基於計數器的熱點探測:回邊計數器

(3)編譯最佳化技術 公用子運算式消除
如果一個運算式E已經計算過,並從先前到現在沒有發生變化,那可採用之前的計算結果 資料邊界檢查消除
資料的邊界檢查是不是必須在運行期一次不漏檢查 方法內聯
減少函數調用 逃逸分析
對象在一個方法中定義,並且被外部方法引用,稱為逃逸,有方法逃逸,線程逃逸 如果證明一個對象不會逃逸到方法或線程外,可以:
棧上分配 同步消除 標量替換:把對象拆分 第12章:Java記憶體模型與線程

Java虛擬機器規範中試圖定義一種Java記憶體模型來屏蔽掉各種硬體和作業系統的記憶體訪問差異

主要目標:定義程式中各個變數的訪問規則,即在虛擬機器中將變數儲存到記憶體和從記憶體中取出變數這樣的底層細節

(1)Java記憶體模型 Java記憶體模型規定了所有的變數都儲存在主記憶體中(類似Java堆中的對象執行個體),每條線程還有自己的工作記憶體(類似虛擬機器棧的部分域),線程的工作記憶體中儲存了被該線程使用到的變數的主記憶體副本拷貝,線程對變數的所有操作都必須在工作記憶體中進行,而不能直接讀寫主記憶體中的變數。不同線程之間也無法直接存取對方工作記憶體中的變數,線程間變數值的傳遞均需要通過主記憶體來完成。

(補充圖)

(2)Java記憶體模型特徵 原子性
保證原子性操作 可見度
指當一個線程修改了共用變數的值,其他線程能夠立即得知這個修改 有序性
總結一句話:在本線程內觀察,所有操作都是有序的;在另一個線程觀察,所有操作是無序的

(3)Java線程實現 核心線程實現 使用者線程實現 使用者線程加輕量級進程混合實現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.