JVM原理總結

JVM原理總結

  • 對JVM學習的並不深刻,只是學了幾篇博客。

1 JVM用途

  • JVM是Java Virual Machine(Java虛擬機)的縮寫,是一個虛擬計算機。Java源文件經編譯成字節碼程序,經過JVM將每一條指令翻譯成不一樣平臺的機器碼,經過特定平臺運行。算法

  • JVM屏蔽了與具體操做系統平臺相關的信息,Java程序只需生成在Java虛擬機上運行的字節碼,就能夠在多種平臺上不加修改的運行。所謂"一次編譯,屢次運行",編譯出的字節碼文件.class。數組

2 JRE/JDK/JVM的關係

  • JRE是Java運行環境,即(Java Runtime Environment),也就是Java平臺。全部的Java程序都要在JRE下才能運行。
  • JDK是開發工具包,即(Java Development Kit),它是程序開發者用來編譯、調試Java程序,它也是Java程序,也須要JRE才能運行。
  • JVM是Java虛擬機,即(Java Virual Machine),它是JRE的一部分,一個虛構出來的計算機,它支持跨平臺。

3 JVM體系結構

類加載器:加載class文件;緩存

執行引擎:執行字節碼或者執行本地方法多線程

運行時數據區:包括方法區、堆、棧、PC寄存器、本地方法棧併發

4 JVM運行時數據區

PC計數器:用於存儲每一個線程下一條字節碼指令地址jvm

:線程私有,生命週期和線程一致。描述的是 Java 方法執行的內存模型:每一個方法在執行時都會建立一個棧幀(Stack Frame)用於存儲局部變量表操做數棧動態連接方法出口等信息。每個方法從調用直至執行結束,就對應着一個棧幀從虛擬機棧中入棧到出棧的過程。工具

:線程共享,主要是存放對象實例和數組。能夠認爲Java中全部經過new建立的對象的內存都在此分配,Heap中的對象的內存須要等待GC進行回收性能

方法區:屬於全局共享內存區域,存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據學習

本地方法棧:區別於 Java 虛擬機棧的是,Java 虛擬機棧爲虛擬機執行 Java 方法(也就是字節碼)服務,而本地方法棧則爲虛擬機使用到的 Native 方法服務開發工具

運行時常量池存放類中固定的常量信息、方法和Field的引用信息等,其空間是從方法區中分配

5 如何判斷對象是否存活?

引用計數法:給對象中添加一個引用計數器,當一個地方引用了對象,計數加1;當引用失效,計數器減1;當計數器爲0表示該對象已死、可回收;但很難解決循環引用問題

可達性分析:經過一系列稱爲「GC Root」的對象做爲起點,從這些節點開始向下搜索,搜索所走過的路徑稱爲引用鏈,當一個對象到GC Roots沒有任何引用鏈相連(從 GC Roots 到這個對象不可達)時,則證實此對象已死、可回收。

即便在可達性分析算法中不可達的對象,也並不是是「facebook」的,這時候它們暫時出於「緩刑」階段,一個對象的真正死亡至少要經歷兩次標記過程:若是對象在進行中可達性分析後發現沒有與 GC Roots 相鏈接的引用鏈,那他將會被第一次標記而且進行一次篩選,篩選條件是此對象是否有必要執行 finalize() 方法。當對象沒有覆蓋 finalize() 方法,或者 finalize() 方法已經被虛擬機調用過,虛擬機將這兩種狀況都視爲「沒有必要執行」。

若是這個對象被斷定爲有必要執行 finalize() 方法,那麼這個對象竟會放置在一個叫作 F-Queue 的隊列中,並在稍後由一個由虛擬機自動創建的、低優先級的 Finalizer 線程去執行它。這裏所謂的「執行」是指虛擬機會出發這個方法,並不承諾或等待他運行結束。finalize() 方法是對象逃脫死亡命運的最後一次機會,稍後 GC 將對 F-Queue 中的對象進行第二次小規模的標記,若是對象要在 finalize() 中成功拯救本身 —— 只要從新與引用鏈上的任何一個對象簡歷關聯便可。

finalize() 方法只會被系統自動調用一次。

6 哪些對象能夠做爲GC ROOT對象

  1. 虛擬機棧(棧幀中的本地變量表)中引用的對象
  2. 本地方法棧中(Native方法)引用的對象
  3. 方法區中的靜態變量和常量引用的對象

7 JVM垃圾回收:

  • 對新生代的對象的收集稱爲minor GC;
  • 對老年代的對象的收集稱爲major GC;
  • 程序中主動調用System.gc()強制執行的GC爲full GC;
  • 強引用:默認狀況下,對象採用的均爲強引用;
  • 軟引用:適用於緩存場景(只有在內存不夠用的狀況下才會被回收,好比內存溢出異常以前)
  • 弱引用:在GC時必定會被GC回收
  • 虛引用:在這個對象被收集器回收時收到一個系統通知

8 垃圾回收算法

8.1 標記 — 清除算法

直接標記清除就可。

兩個不足:

  • 效率不高,產生大量碎片

8.2 複製算法

把空間分紅兩塊,每次只對其中一塊進行 GC。當這塊內存使用完時,就將還存活的對象複製到另外一塊上面。

解決前一種方法的不足,可是會形成空間利用率低下。

  • 由於大多數新生代對象都不會熬過第一次 GC。因此不必 1 : 1 劃分空間。
  • 能夠分一塊較大的 Eden 空間和兩塊較小的 Survivor 空間,每次使用 Eden 空間和其中一塊 Survivor。當回收時,將 Eden 和 Survivor 中還存活的對象一次性複製到另外一塊 Survivor 上,最後清理 Eden 和 Survivor 空間。大小比例通常是 8 : 1 : 1,每次浪費 10% 的 Survivor 空間。
    • 可是這裏有一個問題就是若是存活的大於 10% 怎麼辦?這裏採用一種分配擔保策略:多出來的對象直接進入老年代。

8.3 標記-整理算法

不一樣於針對新生代的複製算法,針對老年代的特色,建立該算法。主要是把存活對象移到內存的一端。

  • 也解決了內存碎片問題

8.4 分代回收

根據存活對象劃分幾塊內存區,通常是分爲新生代和老年代。而後根據各個年代的特色制定相應的回收算法。

  • 新生代:每次垃圾回收都有大量對象死去,只有少許存活,選用複製算法比較合理。

  • 老年代:老年代中對象存活率較高、沒有額外的空間分配對它進行擔保。因此必須使用 標記 —— 清除 或者 標記 —— 整理 算法回收。

9 垃圾回收器

  • Serial收集器:是最基本、歷史最久的收集器,單線程,而且在收集是必須暫停全部的工做線程
  • ParNew收集器:是Serial收集器的多線程版本
  • Parallel Scavenge收集器:新生代收集器,並行的多線程收集器。它的目標是達到一個可控的吞吐量,這樣能夠高效率的利用CPU時間,儘快完成程序的運算任務,適合在後臺運算;
  • Serial Old收集器:Serial 收集器的老年代版本,單線程,主要是標記—整理算法來收集垃圾;
  • Parallel Old收集器:Parallel Scavenge的老年代版本,多線程,主要是標記—整理算法來收集垃圾;Parallel Old 和 Serial Old 不能同時搭配使用,後者性能較差發揮不出前者的做用;
  • CMS收集器:是一種以獲取最短回收停頓時間爲目標的收集器;基於標記清除算法,併發收集、低停頓、運做過程複雜(初始標記、併發標記、從新標記、併發清除)。CMS收集器有3個缺點:1。對CPU資源很是敏感(佔用資源);2。沒法處理浮動垃圾(在併發清除時,用戶線程新產生的垃圾叫浮動垃圾),可能出現「Concurrent Mode Failure」失敗;3。產生大量內存碎片  
  • G1收集器:
    • 特色:
      • 分代收集,採用不一樣的方式處理新生對象和已經存活一段時間的對象;
      • 空間整合:採用標記整理算法,局部採用複製算法(Region之間),不會有內存碎片,不會由於大對象找不到足夠的連續空間而提早觸發GC;
      • 可預測的停頓:可以讓使用者明確指定一個時間片斷內,消耗在垃圾收集上的時間不超過期間範圍內;

10 內存分配與回收策略

對象優先在 Eden 分配

大對象直接進入老年代

長期存活的對象將進入老年代

相關文章
相關標籤/搜索