推薦:

JVM-超全-圖解

JVM-思維導圖

JVM的體系結構

簡化圖:

類加載器

類加載器作用:加載.class文件

類加載流程(三個階段):

1.加載階段

將編譯好的class文件加載到內存中(方法區),然後會生成一個代錶這個類的Class對象。

2.鏈接階段

會為靜態變量分配內存並設置默認值。

3.初始化階段

執行類構造器()進行初始化賦值。

java自帶的類加載器:

  • 啟動類加載器(Bootstrap ClassLoader):又名根類加載器或引導類加載器,負責加載%JAVA_HOME%\bin目錄下的所有jar包,或者是-Xbootclasspath參數指定的路徑,例:rt.jar
  • 拓展類加載器(Extension ClassLoader):負責加載%JAVA_HOME%\bin\ext目錄下的所有jar包,或者是java.ext.dirs參數指定的路徑
  • 系統類加載器(Application ClassLoader):又名應用類加載器,負責加載用戶類路徑上所指定的類庫,如果應用程序中沒有自定義加載器,那麼此加載器就為默認加載器

雙親委派機制

類加載器收到加載請求

1.不會自己先去加載,把請求委托給父類加載器,如果父類加載器還存在其父類加載器,則進一步向上委托,最終將到達頂層的啟動類加載器

2.如果父類可以完成加載任務,就成功返回

3.如果完不成,子加載器才會嘗試自己去加載

優點:避免重複加載 + 避免核心類篡改

Native

程序中使用:private native void start0();

1.凡是帶了native關鍵字的,說明java的作用範圍達不到了,回去調用底層c語言的庫!

2.會進入本地方法棧,然後去調用本地方法接口將native方法引入執行

本地方法棧(Native Method Stack)

內存區域中專門開辟了一塊標記區域: Native Method Stack,負責登記native方法,

在執行引擎( Execution Engine )執行的時候通過本地方法接口(JNI)加載本地方法庫中的方法

本地方法接口(JNI)

本地接口的作用是融合不同的編程語言為Java所用,它的初衷是融合C/C++程序,

Java在誕生的時候是C/C++橫行的時候,想要立足,必須有調用C、C++的程序,

然後在內存區域中專門開辟了一塊標記區域: Native Method Stack,負責登記native方法,

在執行引擎( Execution Engine )執行的時候通過本地方法接口(JNI)加載本地方法庫中的方法

PC程序計數器

程序計數器: Program Counter Register

每個線程都有一個程序計數器,是線程私有的,就是一個指針,

指向方法區中的方法字節碼(用來存儲指向像一條指令的地址, 也即將要執行的指令代碼),

在執行引擎讀取下一條指令, 是一個非常小的內存空間,幾乎可以忽略不計

為什麼需要程序計數器?記錄要執行的代碼比特置,防止線程切換重新執行

字節碼執行引擎修改程序計數器的值

方法區(Method Area)

方法區是被所有線程共享,所有字段和方法字節碼,以及一些特殊方法,如構造函數,接口代碼也在此定義,

簡單說,所有定義的方法的信息都保存在該區域,此區域屬於共享區間。

靜態變量(static)、常量(final)、類信息(構造方法、接口定義)(Class)、運行時的常量池存在方法區中,但是實例變量存在堆內存中,和方法區無關

棧:先出後進,每個線程都有自己的棧,棧內存主管程序的運行,生命周期和線程同步,線程結束,棧內存也就是釋放。

對於棧來說,不存在垃圾回收問題,一旦線程結束,棧就結束。

棧內存中運行:8大基本類型 + 對象引用 + 實例的方法。

棧運行原理:棧楨

棧滿了:StackOverflowError

隊列:先進先出(FIFO:First Input First Output)

一個JVM只有一個堆內存,堆內存的大小是可以調節的,

類加載器讀取類文件後,一般會把類,方法,常量,變量,我們所有引用類型的真實對象,放入堆中。

堆內存細分為三個區域:

  • 新生區(伊甸園區):Young/New
  • 養老區old
  • 永久區Perm

新生區:類的誕生,成長和死亡的地方

分為:

  • 伊甸園區:所有對象都在伊甸園區new出來
  • 幸存0區和幸存1區:輕GC之後存下來的

老年區(養老區):多次輕GC存活下來的對象放在老年區

真理:經過研究,99%的對象都是臨時對象

永久區

這個區域常駐內存的,用來存放IDK自身攜帶的Class對象,Interface元數據,存儲的是Java運行時的一些環境或

類信息,這個區域不存在垃圾回收。

關閉VM虛擬就會釋放這個區域的內存,一個啟動類,加載了大量的第三方jar包。

Tomcat部署了太多的應用,大量動態生成的反射類,不斷的被加載,直到內存滿,就會出現0OM;

  • jdk1.6之前:永久代,常量池是在方法區。
  • jdk1.7永久代,但是慢慢的退化了,去永久代, 常量池在堆中
  • jdk1.8之後:無永久代,常量池在元空間

注意:

元空間:邏輯上存在,物理上不存在 ,因為:存儲在本地磁盤內,不占用虛擬機內存

默認情况下,JVM使用的最大內存為電腦總內存的四分之一,JVM使用的初始化內存為電腦總內存的六十四分之一.

總結:

  • 棧:基本類型的變量,對象的引用變量,實例對象的方法
  • 堆:存放由new創建的對象和數組
  • 方法區:Class對象,static變量,常量池(常量)

調優工具

public class Test2 {
static String a="111111111111"; public static void main(String[] args) {
while (true){
a=a+ new Random().nextInt(99999999)+new Random().nextInt(99999999);
}
}
}

下載地址:https://www.ej-technologies.com/download/jprofiler/version_92

安裝完成後,需要在IDEA中安裝插件。

添加參數運行程序:

-Xms1m -Xmx1m -XX:+HeapDumpOnOutOfMemoryError:當出現OOM錯誤,會生成一個dump文件(進程的內存鏡像)

在項目目錄下找到dump文件,雙擊打開 , 可以看到什麼占用了大量的內存

常見JVM調優參數

配置參數 功能
-Xms 初始堆大小。如:-Xms256m
-Xmx 最大堆大小。如:-Xmx512m
-Xmn 新生代大小。通常為 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 個 Survivor 空間。實際可用空間為 = Eden + 1 個 Survivor,即 90%
-XX:NewRatio 新生代與老年代的比例,如 –XX:NewRatio=2,則新生代占整個堆空間的1/3,老年代占2/3
-XX:SurvivorRatio 新生代中 Eden 與 Survivor 的比值。默認值為 8。即 Eden 占新生代空間的 8/10,另外兩個 Survivor 各占 1/10
-XX:+PrintGCDetails 打印 GC 信息
XX:+HeapDumpOnOutOfMemoryError 讓虛擬機在發生內存溢出時 Dump 出當前的內存堆轉儲快照,以便分析用

常見垃圾回收算法

引用計數算法

原理是此對象有一個引用,即增加一個計數,删除一個引用則减少一個計數。

垃圾回收時,只用收集計數為 0 的對象。此算法最致命的是無法處理循環引用的問題。

複制算法

此算法把內存空間劃為兩個相等的區域,每次只使用其中一個區域。

垃圾回收時,遍曆當前使用區域,把正在使用中的對象複制到另外一個區域中。

此算法每次只處理正在使用中的對象,因此複制成本比較小,同時複制過去以後還能進行相應的內存整理。

優點:不會出現碎片化問題

缺點:需要兩倍內存空間,浪費

標記-清除算法

此算法執行分兩階段。

第一階段從引用根節點開始標記可回收對象

第二階段遍曆整個堆,把未標記的對象清除。

優點:不會浪費內存空間

缺點:此算法需要暫停整個應用,同時,會產生內存碎片

標記-壓縮算法

此算法結合了 " 標記-清除 ” 和 “ 複制 ” 兩個算法的優點。

也是分兩階段,

第一階段從根節點開始標記所有可回收對象

第二階段遍曆整個堆,清除未標記對象並且把存活對象“壓縮”到堆的其中一塊,按順序排放。

此算法避免了“標記-清除”的碎片問題,同時也避免了“複制”算法的空間問題。

分代回收策略

1.絕大多數剛剛被創建的對象會存放在Eden區

2.當Eden區第一次滿的時候,會觸發MinorGC(輕GC)。首先將Eden區的垃圾對象回收清除,並將存活的對象複制到S0,此時S1是空的。

3.下一次Eden區滿時,再執行一次垃圾回收,此次會將Eden和S0區中所有垃圾對象清除,並將存活對象複制到S1,此時S0變為空。

4.如此反複在S0和S1之間切換幾次(默認15次)之後,還存活的對象將他們轉移到老年代中。

5.當老年代滿了時會觸發FullGC(全GC)

MinorGC

  • 使用的算法是複制算法
  • 年輕代堆空間緊張時會被觸發
  • 相對於全收集而言,收集間隔較短

FullGC

  • 使用的算法一般是標記壓縮算法
  • 當老年代堆空間滿了,會觸發全收集操作
  • 可以使用 System.gc()方法來顯式的啟動全收集
  • 全收集非常耗時

垃圾收集器

垃圾回收器的常規匹配:

串行收集器(Serial)

Serial 收集器是 Hotspot 運行在 Client 模式下的默認新生代收集器, 它的特點是:單線程收集,但它卻簡單而高效

並行收集器(ParNew)

ParNew 收集器其實是前面 Serial 的多線程版本

Parallel Scavenge 收集器

與 ParNew 類似,Parallel Scavenge 也是使用複制算法,也是並行多線程收集器。

但與其他收集器關注盡可能縮短垃圾收集時間不同,Parallel Scavenge 更關注系統吞吐量

系統吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間)

Serial Old 收集器

Serial Old 是 Serial 收集器的老年代版本, 同樣是單線程收集器,使用 “ 標記-整理 ” 算法

Parallel Old 收集器

Parallel Old 是 Parallel Scavenge 收集器的老年代版本, 使用多線程和 “ 標記-整理 ” 算

法,吞吐量優先

CMS 收集器(Concurrent Mark Sweep)

CMS是一種以獲取最短回收停頓時間為目標的收集器(CMS又稱多並發低暫停的收集器),

基於 ” 標記-清除 ” 算法實現, 整個 GC 過程分為以下 4 個步驟:

初始標記(CMS initial mark)

並發標記(CMS concurrent mark: GC Roots Tracing 過程)

重新標記(CMS remark)

並發清除(CMS concurrent sweep: 已死對象將會就地釋放, 注意:此處沒有壓縮)

G1 收集器

G1將堆內存 “ 化整為零 ” ,將堆內存劃分成多個大小相等獨立區域(Region),

每一個Region都可以根據需要,扮演新生代的Eden空間、Survivor空間,或者老年代空間。

收集器能够對扮演不同角色的Region采用不同的策略去處理,這樣無論是新創建的對象還是已經存活了一段時間、熬過多次收集的舊對象都能獲取很好的收集效果。

為什麼要垃圾回收時要設計STW(stop the world)?

如果不設計STW,可能在垃圾回收時用戶線程就執行完了,堆中的對象都失去了引用,全部變成了垃圾,索性就

設計了STW,快速做完垃圾回收,再恢複用戶線程運行。

JVM-初見的更多相關文章

  1. 【JVM】虛擬機初見-運行時數據區圖解

    本文是聽咕泡XX公開課視頻整理的筆記,較書本更為總結,感謝. 計算機模型(匯編知識):數據集(數據).指令集(操作指令,+-等).控制集(分支循環) JVM運行時的數據區: 程序計數器(每個線程都有) ...

  2. Flume初見與實踐

    Photo by Janke Laskowski on Unsplash 參考書籍:<Flume構建高可用.可擴展的海量日志采集系統> --Hari Shreedharan 著 以下簡稱& ...

  3. 46張PPT講述JVM體系結構、GC算法和調優

    本PPT從JVM體系結構概述.GC算法.Hotspot內存管理.Hotspot垃圾回收器.調優和監控工具六大方面進行講述.(內嵌iframe,建議使用電腦瀏覽) 好東西當然要分享,PPT已上傳可供下載 ...

  4. java 利用ManagementFactory獲取jvm,os的一些信息--轉

    原文地址:http://blog.csdn.net/dream_broken/article/details/49759043 想了解下某個Java項目的運行時jvm的情况,可以使用一些監控工具,比如 ...

  5. Jvm 內存淺析 及 GC個人學習總結

    從誕生至今,20多年過去,Java至今仍是使用最為廣泛的語言.這仰賴於Java提供的各種技術和特性,讓開發人員能優雅的編寫高效的程序.今天我們就來說說Java的一項基本但非常重要的技術內存管理 了解C ...

  6. JVM類加載

    JVM的類加載機制就是:JVM把描述類的class文件加載到內存,並對數據進行校驗.轉換解析和初始化,最終形成可以被JVM直接使用的Java類型 ClassLoader JVM中的ClassLoade ...

  7. Java虛擬機 JVM

    finalize();(不建議使用,代價高,不確定性大) 如果你在一個類中覆寫了finalize()方法, 那麼你可以在第一次被GC的時候,挽救一個你想挽救的對象,讓其不被回收,但只能挽救一次. GC ...

  8. 在 Linux 中安裝 Oracle JDK 8 以及 JVM 的類加載機制

    參考資料 該文中的內容來源於 Oracle 的官方文檔 Java SE Tools Reference .Oracle 在 Java 方面的文檔是非常完善的.對 Java 8 感興趣的朋友,可以直接找 ...

  9. MapReduce剖析筆記之六:TaskTracker初始化任務並啟動JVM過程

    在上面一節我們分析了JobTracker調用JobQueueTaskScheduler進行任務分配,JobQueueTaskScheduler又調用JobInProgress按照一定順序查找任務的流程 ...

  10. java太low,又舍不得jvm平臺的豐富資源?試試kotlin吧(一)

    嘗試kotlin的起因 因為各種原因(版權,人員招聘),公司的技術體系從c#轉到了java,我花了大概兩周的時間來上手java,發現java的語法還是非常簡單的,基本看著代碼就知道什麼意思.學習jav ...

隨機推薦

  1. Step by Step 安裝 BizTalk Server 2009

    原創地址:http://www.cnblogs.com/jfzhu/p/4020444.html 轉載請注明出處 演示環境為Windows Server 2008 Enterprise, SQL Se ...

  2. 【poj1739】 Tony&#39;s Tour

    http://poj.org/problem?id=1739 (題目鏈接) 題意 給出一個n*m的地圖,有些是障礙.問從左下角走遍所有非障礙格子一次且僅一次最終到達右下角的路徑方案數. Solutio ...

  3. .NET Core、DNX、DNU、DNVM、MVC6學習資料

    一.資源 1.http://dotnet.github.io/ 2.http://www.codeproject.com/Articles/1005145/DNVM-DNX-and-DNU-Under ...

  4. SQL基礎知識總結(一)

    1.union 和union all 操作符 1)union內部的select語句必須擁有相同的列,列也必須有相似的數字類型.同時,每條select語句中列的順序相同. union語法(結果集無重複) ...

  5. iOS學習筆記---網絡請求

    一.HTTP協議的概念 HTTP協議:Hyper Text Transfer Protocol(超文本傳輸協議)是用於從萬維網服務器傳送超文本到本地瀏覽器的傳輸協議.HTTP是一個應用層協議,由請求和 ...

  6. 程序員帶你十天快速入門Python,玩轉電腦軟件開發(三)

    聲明:本次教程主要適用於已經習得一門編程語言的程序員.想要學習第二門語言.有夢想,立志做全棧攻城獅的你 . 如果是小白,也可以學習本教程.不過可能有些困難.如有問題在文章下方進行討論.或者添加QQ群5 ...

  7. Meta元素可視區

    一.網頁手機wap2.0網頁的head裏加入下面這條元標簽,在iPhone的瀏覽器中頁面將以原始大小顯示,並不允許縮放. <meta name="viewport" cont ...

  8. 配置ubuntu

    2. 安裝配置軟件 創建服務器成功後,點擊服務器列錶頁的Ubuntu輕量應用服務器卡片的遠程連接按鈕 連接成功後開始安裝軟件. VNC的安裝與配置 安裝之前先輸入 apt-get update 獲取最 ...

  9. C-Lodop提示“網頁還沒下載完畢,請稍等一下再操作.”

    該提示在Lodop舊版本中是: 提示"WebSocket沒准備好,點確定繼續",提示“C-Lodop沒准備好”,新版本修改了該提示的描述“網頁還沒下載完畢,請稍等一下再操作.”,讓 ...

  10. navicat oracle library is not loaded

        navicat oracle library is not loaded CreationTime--2018年8月9日19點13分 Author:Marydon 1.情景展示 Navicat ...