JVM知識點整理複習

此次JVM知識點包含以下幾個部分

1.類加載機制

2.jvm運行時數據區

3.java對象內存佈局

4.jvm內存模型

5.垃圾回收機制

6.垃圾收集器

7.問題排查

一 類加載機制

主要說的部分是這一塊

那麼如何裝載呢,這就談到了咱們的雙親委派機制,簡單來說就是類,向上遞交,向下加載,源碼和圖如下

if (parent != null) {
    c = parent.loadClass(name, false);
  } else {
   //由於BootstrapClassLoader是C++寫的,在java中被視爲null
    c = findBootstrapClassOrNull(name);
  }

那麼裝載的過程是什麼呢,如圖

 

 

裝載幹了啥呢,大白話說就是一個你把一個java文件轉換成二進制給jvm處理,官方一點的語言就是:

        ①通過一個類的全限定名獲取這個類的二進制字節流。

        ②將這個字節流的靜態存儲結構轉換爲方法區的運行時數據結構。

        ③在堆中生成一個這個二進制字節流的Class對象作爲訪問入口。

那麼鏈接呢,驗證:字面意思,準備:賦默認值,解析:符號引用轉換爲直接引用

二 運行時數據區

話不多說,看法寶,上圖

方法區

          存放:靜態變量,常量,即時編譯的class文件,類信息。

          區別:1.8之前叫Perm Space 永久代,現在叫Meta Space 元空間

 

虛擬機棧

          存放:棧幀;即方法的調用,-Xss可以設置棧大小,默認1M;使棧溢出的使遞歸。

          構成:局部變量表;方法中定義的變量與方法的參數,

                    操作數棧;壓棧出棧存放數據的地方,

                    動態鏈接;這個的作用就是知道誰調用的,比方說java中的多態,最後會知道具體是哪個類,

                    方法返回地址;字面意思

          存放:對象及數組

接下來咱們看一下這個指針指向問題

  1. 棧指向堆;   棧幀(方法中有一個變量)即 Object obj = new Object();
  2. 方法區指向堆;靜態變量,private static Object obj = new Object();
  3. 堆指向方法區;由於方法區中存放的類信息,所以對於多態如何識別,這一點,就說明堆中有指向方法區的指針。

三 java對象內存佈局

四 jvm內存模型

內存模型可以認爲是運行時數據區的落地,那麼當一個對象來的時候,如何分配內存空間呢

  1. 首先放入Eden區,看夠不夠,不夠,minorGC,再試試Survivor是否足夠,如果不夠;
  2. 放入老年代看看夠不夠,不夠就來一次Full GC(minorGC+MajorGC);
  3. 如果還不夠就OOM了。

那麼對象進入老年代的條件是什麼呢

  1. 新生代中年齡大於15;
  2. 大對象(-XX:PretenureSizeThreshold 配置這個,大於這個數的就成爲大對象
  3. 動態年齡:即survivor區中 同一年齡的超過了該區一半,那麼大於等於該年齡的對象直接進入老年代
  4. minorGC,新生代放不下的時候

那麼這裏邊放了這麼對象,該如何回收呢

五 垃圾回收機制

什麼是垃圾,如何確定垃圾呢

引用計數法

沒有任何指針指向的就是垃圾,但是無法解決循環引用的問題

可達性分析

由GCRoot(靜態成員,Thread線程,虛擬機棧的變量表,本地方法棧中的變量,類加載器,常量)作爲頭,向下順藤摸瓜,能摸得到的就是好瓜,摸不到的就回收扔了。

既然已經確定了垃圾,那麼如何回收呢

四種垃圾回收算法

  1. 標記-清除:將標記的清除掉,弊端就是內存不連續,容易產生內存碎片;
  2. 複製:內存分兩塊,將一端複製到另一端,解決了內存不連續,弊端就是內存有效區只由一半;
  3. 標記-整理:將垃圾回收後壓縮整理一下,解決了內存有效區只有一半的問題;
  4. 分代算法:個人認爲這個屬於一種思想,即對前三種的一種總結;老年代用標記清除,標記整理,新生代用複製

算法說完了,那麼算法的落地,如何實現的呢,這就要說到垃圾收集器了

六.垃圾收集器

 

可以看到從剛開始的Serial到現在的G1乃至ZGC的最多10ms停頓可以看到java一直在尋找最短的停頓時間,這個也是一直優化的方向。

並行收集:多個線程一起收集

併發收集:跟用戶線程一起跑

CMS和G1的區別有哪些呢?

CMS,四個步驟爲,初始標記-併發標記-重新標記-併發清理

G1,四個步驟,初始標記-併發標記-最終標記-篩選回收(對各個Region的回收價值進行排序根據用戶期望的GC停頓時間制定回收計劃

G1可以設置停頓時間(-XX:MaxGCPauseMillis=20),就是因爲他的Region,可以理解爲一面牆分成了多個磚頭,一些磚頭的集合稱爲老年代,一些稱爲新生代。

這些都知道了,那麼出現錯誤該如何排查呢

七 問題排查

1.頻繁FullGC

導致頻繁FullGC的原因有

  1. System.gc()
  2. jmap -dump:format=b,fifile=heap.hprof PID

  3. 老年代內存不夠

步驟

  1. 打印FullGC前後的日誌 -XX:+HeapDumpBeforFullGC   -XX:+HeapDumpAfterFullGC   -XX:+HeapDumpPath=a.prof
  2. 使用MAT工具進行分析,可以看堆中佔用情況,以及class的新建情況。

2.線上CPU負載過高排查

  1. 採用TOP命令,查出佔用cpu最高的java應用
  2. top -Hp PID查詢出佔用cpu最高的線程
  3. 找出該線程ID,轉換成16進制 printf "%x\n"  tid
  4. jstack PID > d.txt
  5. 打開d.txt,查詢該16進制的tid就能找到了

3.吞吐量調優

  1. 使用命令打印出gc.log   -XX:+PrintGCDetails  -Xloggc:gc.log
  2. 使用gcviewer來分析日誌
  3. 根據具體情況調整堆棧大小,停頓時間等參數,再看gcviewer分析出來的數據如何。

4.死鎖排查

  1. 使用 java  bin目錄下自帶的visualVM工具,可遠程鏈接可本地鏈接
  2. 連接之後,點擊線程一欄,便會出現紅字  發現死鎖
  3. 點擊旁邊的Dump按鈕即可進入dump文件中,往下翻即可看到提示的哪一行出現了死鎖,然後定位到代碼

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章