Java後端開發三年,你不得不瞭解的JVM

Java虛擬機 Java 虛擬機 程序員 電腦 JavaSpring高級進階 2019-05-22
Java後端開發三年,你不得不瞭解的JVM

JAVA程序員,三年是個坎,如果過了三年你還沒有去研究JVM的話,那麼你這個程序員只能是板磚的工具了。下面來個JVM的解析可好?

JVM是Java Virtual Machine(Java虛擬機)的縮寫,也就是指的JVM虛擬機,屬於是一種虛構出來的計算機,在我們實際的電腦上來進行模擬各種計算機的功能的這麼個東西。

因為有了JVM的存在,搞JAVA的不再需要去關心什麼時候去釋放內存,也不會像C++程序員那樣為了一點點內存而惆悵,對就是你,JVM虛擬機幫你把這些東西都完成了,那麼我們來說說JAVA的JVM吧!

我們先來看看JVM的模型吧,之前在百度上看文檔,上面就說了幾個,方法區,堆,棧,計數器。沒了,很難受,於是看了深入理解JVM的書,也算是有點體會。

在深入理解JVM一書中提到,JVM運行時的數據區域會劃分為幾個不同的區域,有方法區(Method Area),虛擬機棧(VM Stack),本地方法棧(Native Method Stack),堆(heap),程序計數器(Program Counter Register),下面就是書中的圖:

Java後端開發三年,你不得不瞭解的JVM

咱們一個一個來解釋: 先說程序計數器(Program Counter Register):程序計數器實際上就是用於存放下一條指令所在地址的地方,當我們執行一條指令的時候,要先知道他存放的指令位置,然後把指令帶到寄存器上這是就是獲取指令,然後程序計數器中的存貯地址會加1,然後這樣子循環的去執行,而且程序計數器這個小的內存區是“線程私有的內存”

為什麼會是私有的呢?,在深入理解JVM一書中說的是虛擬機的多線程通過線程的輪流切換來切換分配處理器的執行時間的方式來實現,說起來其實很拗口的,其實也就是說一個處理器,同一個時刻,只會執行一個線程的指令,但是時間可能不均衡,可能第一分鐘在a線程,第二分鐘就去執行b線程了,但是呢,為了保證切換回來還需要是一致的,那麼每個線程中就會有一個獨立存在的程序計數器,獨立來存貯,為了保證不影響。所以他是一個“線程私有的內存”。

程序計數器還有幾個特點:

  • 如果線程正在執行的是Java 方法,則這個計數器記錄的是正在執行的虛擬機字節碼指令地址。
  • 如果正在執行的是Native 方法,則這個計數器值為空(Undefined)。
  • 此內存區域是唯一一個在Java虛擬機規範中沒有規定任何OutOfMemoryError情況的區域。

分別解釋一下這三句話吧,這是深入理解java虛擬機中的原話,第一句好像已經很直白了,沒的說,來說說第二句話吧

因為這個計數器記錄的是字節碼指令地址,但是Native(本地方法);就比如說(System.currentTimeMillis())他是通過C來實現,直接通過系統就能直接調用了不需要去編譯成需要執行的字節碼指令的話,那麼就相當於不過程序計數器,它沒有記錄的話,那他的計數器的值就肯定為空了。

第三句話 我們可以試試編譯一小段代碼,然後反編譯出來看看

Java後端開發三年,你不得不瞭解的JVM

也就是實際上是這個樣子的

public class Test{ public int test(){ int a = 10; //0 ...... int b = 20; //3....... int c = 30; //6...... return (a+b)*c; //11.... 13.... 14...執行加減乘除操作 } }

上面的0,2,3,5,6,8....就是指令的偏移地址bipush就是入棧指令, 在執行到test方法的時候,線程就會創建對應的程序計數器在計數器中放0,2,3,5,6,8....這些指令地址,所以計數器裡改變的不是內存的大小,它也就沒有溢出了。

下面我們再來說一下:JAVA虛擬機棧(VM Stack)

線程私有,生命週期和線程一樣,這個虛擬機棧描述的是JAVA方法執行的內存模型,用於存局部變量,操作數棧,方法出口等信息的,上面那個bipush就是入棧指令,在這裡最需要注意的就是他存放的是什麼數據.局部變量裡面放的就是那些我們所知道的基本的數據類型,對象引用的話那就是一個地址。

在虛擬機規範裡面還說,他的2個異常狀況:

  • 一個是StackOverflowError異常,棧內存溢出,這肯定很容易理解,就是棧的內存不夠,你的請求線程太大。(固定長度的棧)
  • 如果說在動態擴展的過程中,申請的長度還是不夠,那麼會拋出另外一個異常OutOfMemoryError異常。

本地方法棧(Native Method Stack) :

它和虛擬機棧很類似,區別就在於虛擬機棧執行的是JAVA方法,但是本地方法棧則是Native方法,其他的沒啥不同就連拋出異常都一樣的。

JAVA堆(heap) 在JVM一書中也有提到,Heap是在JAVA虛擬機中內存佔用最大的一個地方,也是所有線程共享的一個內存區域,堆內存中主要就是用於存放對象實例的。

幾乎是所有的對象實例都在這裡分配內存,JAVA堆是垃圾收集器管理的主要區域,那麼現在重點來了,面試中問到最多的垃圾回收機制接下來就要仔細說說了。

內存回收,現在都是進行的分代算法,堆中也是,新生代,老年代,而且兩種垃圾回收機制是採用的不同的回收機制的,在新生代中,每次垃圾收集時都發現有大批對象死去,只有少量存活,那就選用複製算法,只需要付出少量存活對象的複製成本就可以完成收集。

而老年代中因為對象存活率高、沒有額外空間對它進行分配擔保,就必須使用"標記-清理"或"標記-壓縮"算法來進行回收,說回收機制先看看heap的分區(這個from和to 並不是絕對的,看對象處在哪個位置,GC的次數不一樣之後,那from和to會有相應轉變)

Java後端開發三年,你不得不瞭解的JVM

分區一目瞭然,下面研究一下算法實現吧

Minor GC:GC新生代,

Full GC:老年代GC,

因為新生代中對象的存活率比較低,所以一般採用複製算法,老年代的存活率一般比較高,一般使用”標記-清理”或者”標記-整理”算法進行回收。

看了有幾天才明白啥意思,我說說我自己的見解吧,還是畫圖吧,

Minor GC:

我們每次new對象的時候都會先在新生代的Enden區放著也就是最開始 是這樣子的

Java後端開發三年,你不得不瞭解的JVM

然後在Enden用完的時候裡面會出現待回收的

Java後端開發三年,你不得不瞭解的JVM

然後就來了把存活的對象複製放到Survior1(from)中,待回收的等待給他回收掉 就是這樣的

Java後端開發三年,你不得不瞭解的JVM

然後把Enden區清空回收掉

Java後端開發三年,你不得不瞭解的JVM

這樣的話 第一次GC就完成了,下面再往下走

當Enden充滿的時候就會再次GC

先是這個樣子的

Java後端開發三年,你不得不瞭解的JVM

然後會把 Enden和Survoir1中的內容複製到Survior中,

Java後端開發三年,你不得不瞭解的JVM

然後就會把Enden和Survior進行回收

Java後端開發三年,你不得不瞭解的JVM

然後從Enden中過去的就相當於次數少的,而從Survior1中過去的就相當於移動了2次

Java後端開發三年,你不得不瞭解的JVM

這樣新生代的GC就執行了2次了,

當Enden再次被使用完成的時候,就會從Survior2複製到Survior1中

Java後端開發三年,你不得不瞭解的JVM

經過回收之後Surior1就變了,1對象是從Enden直接複製過來的,2對象是Enden-->Survior2-->Survior1 ,3對象則是從Enden-->Surivior1-->Survior2-->Survior1 複製過來的,這樣一步一步的執行下去的時候,就是新生代的GC。

既然這樣,那為什麼還會存在老年代呢?其實如果GC在執行的時候有些對象一直沒有被回收,那麼他移動次數就會無限的累計,每次從Surior(from)到Surior(to)的過程中就相當於又增加了一次移動,當他達到一定的次數的時候(默認是15),就會移動到老年代裡了,所以不存在不會被回收的對象,但是這個次數可以設置的,

-XX:MaxTenuringThreshold

就類似這樣子

Java後端開發三年,你不得不瞭解的JVM

其實上邊的這只是一種情況,還有就是如果對象太大,存不下,那就直接會進入老年代。

還有那種默認就是長期活著的也會進入老年代,

而且這種複製算法的垃圾回收機制是比較浪費內存的,每次都會有一塊內存區是閒著不幹活的,但是優點很明顯,簡單高效

以上就是GC中垃圾回收中的新生代複製算法解析,新生代的Minor GC也算是知道了不少東西了,以上就是一些個人的見解,圖比較清晰,容易理解,有不對的地方希望能夠各位同行指點一下。

寫在後面

對於很多初級Java工程師而言,想要提升技能,往往是自己摸索成長,不成體系的學習效果低效漫長且無助。

下文整理的這些架構技術希望對Java開發的朋友們有所參考以及少走彎路,本文的重點是你有沒有收穫與成長,其餘的都不重要,希望讀者們能謹記這一點。同時我經過多年的收藏目前也算收集到了一套完整的學習資料,希望對想成為架構師的朋友有一定的參考和幫助。

下面是資料部分截圖,誠意滿滿特別適合有3-5年開發經驗的Java程序員們學習。

領取方式:轉發文章,一定記得轉發文章,然後私信‘技術提升’獲取免費資源

Java後端開發三年,你不得不瞭解的JVM

而針對以上面試技術點,我在這裡也做一些技術知識面試專題資料分享,希望能更好的幫助到大家。

Java後端開發三年,你不得不瞭解的JVM

Java後端開發三年,你不得不瞭解的JVM

Java後端開發三年,你不得不瞭解的JVM

領取方式:轉發文章,一定記得轉發文章,然後私信‘技術提升’獲取免費資源

相關推薦

推薦中...