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),下面就是書中的圖:
我們們一個一個來解釋: 先說程式計數器(Program Counter Register):程式計數器實際上就是用於存放下一條指令所在地址的地方,當我們執行一條指令的時候,要先知道他存放的指令位置,然後把指令帶到暫存器上這是就是獲取指令,然後程式計數器中的存貯地址會加1,然後這樣子迴圈的去執行,而且程式計數器這個小的記憶體區是“執行緒私有的記憶體”。
為什麼會是私有的呢?,在深入理解JVM一書中說的是虛擬機器的多執行緒透過執行緒的輪流切換來切換分配處理器的執行時間的方式來實現,說起來其實很拗口的,其實也就是說一個處理器,同一個時刻,只會執行一個執行緒的指令,但是時間可能不均衡,可能第一分鐘在a執行緒,第二分鐘就去執行b執行緒了,但是呢,為了保證切換回來還需要是一致的,那麼每個執行緒中就會有一個獨立存在的程式計數器,獨立來存貯,為了保證不影響。所以他是一個“執行緒私有的記憶體”。
程式計數器還有幾個特點:
-
如果執行緒正在執行的是Java 方法,則這個計數器記錄的是正在執行的虛擬機器位元組碼指令地址。
-
如果正在執行的是Native 方法,則這個計數器值為空(Undefined)。
-
此記憶體區域是唯一一個在Java虛擬機器規範中沒有規定任何OutOfMemoryError情況的區域。
分別解釋一下這三句話吧,這是深入理解java虛擬機器中的原話,第一句好像已經很直白了,沒的說,來說說第二句話吧
因為這個計數器記錄的是位元組碼指令地址,但是Native(本地方法);就比如說(System.currentTimeMillis())他是透過C來實現,直接透過系統就能直接呼叫了不需要去編譯成需要執行的位元組碼指令的話,那麼就相當於不過程式計數器,它沒有記錄的話,那他的計數器的值就肯定為空了。
第三句話 我們可以試試編譯一小段程式碼,然後反編譯出來看看
也就是實際上是這個樣子的
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會有相應轉變)
分割槽一目瞭然,下面研究一下演算法實現吧
Minor GC: GC新生代,
Full GC: 老年代GC,
因為新生代中物件的存活率比較低,所以一般採用複製演算法,老年代的存活率一般比較高,一般使用”標記-清理”或者”標記-整理”演算法進行回收。
看了有幾天才明白啥意思,我說說我自己的見解吧,還是畫圖吧,
Minor GC:
我們每次new物件的時候都會先在新生代的Enden區放著也就是最開始 是這樣子的
然後在Enden用完的時候裡面會出現待回收的
然後就來了把存活的物件複製放到Survior1(from)中,待回收的等待給他回收掉 就是這樣的
然後把Enden區清空回收掉
這樣的話 第一次GC就完成了,下面再往下走
當Enden充滿的時候就會再次GC
先是這個樣子的
然後會把 Enden和Survoir1中的內容複製到Survior中,
然後就會把Enden和Survior進行回收
然後從Enden中過去的就相當於次數少的,而從Survior1中過去的就相當於移動了2次
這樣新生代的GC就執行了2次了,
當Enden再次被使用完成的時候,就會從Survior2複製到Survior1中,
接下來是連圖
經過回收之後Surior1就變了,1物件是從Enden直接複製過來的,2物件是Enden-->Survior2-->Survior1 ,3物件則是從Enden-->Surivior1-->Survior2-->Survior1 複製過來的,這樣一步一步的執行下去的時候,就是新生代的GC。
既然這樣,那為什麼還會存在老年代呢?其實如果GC在執行的時候有些物件一直沒有被回收,那麼他移動次數就會無限的累計,每次從Surior(from)到Surior(to)的過程中就相當於又增加了一次移動,當他達到一定的次數的時候(預設是15),就會移動到老年代裡了,所以不存在不會被回收的物件,但是這個次數可以設定的,
-XX:MaxTenuringThreshold
就類似這樣子
其實上邊的這只是一種情況,還有就是如果物件太大,存不下,那就直接會進入老年代。
還有那種預設就是長期活著的也會進入老年代,
而且這種複製演算法的垃圾回收機制是比較浪費記憶體的,每次都會有一塊記憶體區是閒著不幹活的,但是優點很明顯,簡單高效
以上就是GC中垃圾回收中的新生代複製演算法解析,新生代的Minor GC也算是知道了不少東西了,以上就是一些個人的見解,圖比較清晰,容易理解,有不對的地方希望能夠各位同行指點一下。
如果你對技術提升很感興趣,歡迎
1~5
年的工程師可以加入我的Java進階之路來交流學習:
908676731
。裡面都是同行,有
資源共享
,還有大量
面試題以及解析
。歡迎一到五年的工程師加入,合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31555445/viewspace-2641722/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 你不得不瞭解的前後端分離原理!後端
- 後端開發都應該瞭解的登入漏洞後端
- 重新學習web後端開發-005-瞭解前後端分離開發模式Web後端模式
- 你不得不瞭解的CSS資料型別CSS資料型別
- Java 開發, volatile 你必須瞭解一下Java
- 後端開發都應該瞭解的資訊洩露風險後端
- 你不得不掌握的 JVM 記憶體管理JVM記憶體
- JAVA後端開發規範Java後端
- 移動端開發基礎瞭解
- Java併發(7)- 你真的瞭解 ReentrantReadWriteLock 嗎?Java
- 你瞭解 Java 的逃逸分析嗎?Java
- 最近面試Java後端開發的感受面試Java後端
- 最近面試 Java 後端開發的感受!面試Java後端
- 你瞭解Java反射嗎?Java反射
- Python常用的web開發工具,你瞭解多少?PythonWeb
- 你不得不瞭解 Helm 3 中的 5 個關鍵新特性
- [譯] Java、Kotlin、RN、Flutter 開發出來的 App 大小,你瞭解過嗎?JavaKotlinFlutterAPP
- Spring 中不得不瞭解的姿勢Spring
- 前端不得不瞭解的 Flex 佈局前端Flex
- 前端不得不瞭解的TCP協議前端TCP協議
- 帶你瞭解 WebAssembly 的發展、應用與開發Web
- 一文帶你瞭解 JVM 的垃圾回收機制JVM
- 你可能不瞭解的java列舉Java
- Java String 物件,你瞭解多少?Java物件
- java異常你瞭解多少Java
- java後端開發ms題記錄Java後端
- 【Spring註解驅動開發】關於BeanPostProcessor後置處理器,你瞭解多少?SpringBean
- 瞭解Java物件,簡單聊聊JVM調優分析Java物件JVM
- 2020年最流行的Java開發技術你不瞭解下?Java
- 你應該瞭解的 Java SPI 機制Java
- 你瞭解 Java 的類載入器嗎?Java
- 瞭解JDK、JRE、JVM及Java程式的編譯與執行JDKJVMJava編譯
- Java 最全工具類(後端開發必備)Java後端
- 面試官:談談你對JVM垃圾收集器的瞭解面試JVM
- Java後端開發崗必備技能:Java併發中的記憶體模型Java後端記憶體模型
- Java開發程式設計師:JVM相關的知識講解Java程式設計師JVM
- App《最美詩詞》開發 -- Java後端(整合框架)APPJava後端框架
- Java後端高階開發面試技巧解析Java後端面試