深刻理解Java虛擬機---學習感悟以及筆記

1、爲何要學習Java虛擬機?算法

      這裏咱們使用舉例來講明爲何要學習Java虛擬機,其實這個問題就和爲何要學習數據結構和算法是一個道理,工欲善其事,必先利其器。曾經的我常常懼怕處理內存溢出的問題,由於不知道他爲何會出現這個問題,當我在看了這本書之後明白了垃圾回收算法,以及JVM是如何幫助咱們處理GC的,這個時候當出現這個問題的時候我就明白鬚要查找GC Root,或者查看GC日誌,去查找這個問題的根源,這樣就能處理這些問題。還有之前的在理解重載和重構的時候只是在表面去理解,當我看完這本書明白,原來在方法調用時候這些東西就生成處理,另外還有一個new到底經歷那些事情等等一序列問題,若是你還在就糾結一些問題爲何是這麼處理的時候那你就去看Java虛擬機吧,或許會有不同的感悟,以上就是爲何要學習Java虛擬機的緣由,可能有部分解釋的不是很全面,我想在感悟方面在仔細說一下這個問題。
安全

2、感悟?數據結構

      其實也算不上什麼感悟,只是對一些問題認識更加深入而已,這裏面咱們來談一下GC,要探討這個問題咱們須要從4個方面入手:多線程

      1.JVM是如何分配內存的?數據結構和算法

      2.如何才能保證正確的回收?工具

      3.JVM什麼狀況下觸發GC以及GC的方式?學習

  4.如何監控和優化GC?優化

 首先從JVM內存分佈開始:下圖是JVM內存分佈圖.net

 

 

 1.線程計數器,是一塊較小的內存空間,用來指定當前線程執行字節碼的行數,每一個線程計數器都是私有的,由於每一個線程都須要記錄執行的行數;這裏解釋一下爲何每一個線程都須要一個線程計數器,JVM的多線程是經過線程輪流切換分配執行時間來實現的,在任什麼時候刻,每一個處理器都只會執行一個線程中的指令,當線程進行切換的時,爲了線程能恢復當正確的位置,因此每一個線程必須有個獨立的線程計數器,這樣才能保證線程之間不互相影響。線程

  這裏注意下,若是線程執行是一個Java方法的時候,計數器記錄的是虛擬機字節碼指令的地址;當執行的是Native的方法的時候,計數器指令爲空;該內存區域是Java虛擬機惟一沒有規定任何OutOfMemoryError的區域。

 2.Java虛擬棧,這個也是一個線程私有的,生命週期與線程是同步的,每一個方法在執行的同時,都會建立一個棧幀,用於存儲局部變量表,操做數棧,動態連接,方法出入口等信息,每一個方法的調用到執行完成的過程就是一個棧幀入棧到出棧的過程;

  這裏解釋一下局部變量表,局部變量表存儲方法相關的局部變量,包括基本數據,對象引用和返回地址等。在局部變量表中,只有long和double類型會佔用2個局部變量空間(Slot,對於32位機器,一個Slot就是32個bit),其它都是1個Slot。須要注意的是,局部變量表是在編譯時就已經肯定好的,方法運行所須要分配的空間在棧幀中是徹底肯定的,在方法的生命週期內都不會改變。這部分東西我還想等下一篇博客的時候我想仔細說一下字節碼的執行過程;

  虛擬機棧規定了2種異常狀況,一種是線程請求棧的深度大於虛擬機棧所容許的深度,這時候將會拋出StackOverflowError異常,若是當Java虛擬機容許動態擴展虛擬機棧的時候,當擴展的時候沒辦法分配到內存的時候就會報OutOfMemoryError異常;

    3.本地方法棧,與虛擬機棧執行的基本相同,惟一的區別就是虛擬機棧是執行Java方法的,本地方法棧是執行native方法的;

    4.Java堆,堆區是Java虛擬機所管理的內存中最大的一塊,Java堆是被全部線程共享的內存區域,主要存儲對象的實例。

       當堆中沒有內存完成實例分配,而且堆沒法擴展的時候,將會拋出OutOfMemoryError異常;當前虛擬機都是能夠擴展的;

   5.方法區,這個也是線程共享的內存區域,存儲被虛擬機加載的類信息、常量、靜態變量、即時編譯的代碼數據等;

      方法區在物理上也是不須要連續的,能夠選擇固定大小或者擴展的大小,還能夠選擇不實現垃圾收集,方法區的垃圾回收是比較少的,這就是方法區爲何被稱爲永久區的緣由,可是方法區也是能夠執行回收的,該區域主要是針對常量池和類型的卸載;在方法區也規定當方法區沒法知足內存分佈的時候,將會拋出OutOfMemoryError異常;

      運行時常量是方法區的一部分,常量池主要用於存放編譯生成的各類字面量和符合引用,因爲常量池屬於方法區的一部分,因此當常量池沒有內存空間的時候就拋出OutOfMemoryError異常;

   6.直接內存,不是虛擬機運行時的一部分,能夠直接訪問堆外的內存;因此當內存空間沒法動態擴展的時候就會出現OutOfMemoryError異常;

   以上基本是JVM內存分佈的內容,簡單的理解水滿則溢出就是這個道理,系統的整個空間是一個大的容器,分不一樣的部分或者桶去分擔整個容量,當那個桶不夠的時候天然會溢出。明白內存區域的分佈咱們看下對象是如何分配在內存空間裏面的?

  Java對象這裏指的是引用類型的對象,這裏用Student stu=new Student()爲例子訪問,Student stu做爲引用對象,存在與Java虛擬機棧上,new Student()保存在Java堆中,堆中記錄Student類型的信息包括方法,接口,對象類型等地址,這些類型的執行的數據存儲在方法區中;

  這裏須要說明一下對象訪問的方式,主要包括2種句柄訪問和直接指針訪問:

 1. 句柄訪問主要是Java堆中劃分一塊句柄池,虛擬機棧中存放句柄池中的地址,句柄池中包括對象的實例數據和對象類型的數據的地址,基本分佈以下圖:

  

   2.直接指針訪問,就是虛擬機棧直接指向Java堆中的對象類型指針和對象的實例數據,而後對象類型指針在指向方法區中對象類型的實例數據,分佈以下圖:

 HotSpot就是第二種訪問方式,優勢在於訪問速度快,省去一次指針開銷時間,JVM內存分佈基本介紹到這裏,接下來講下如何保證正確回收?

  回收是已經沒有用的對象,那怎麼判斷一個對象沒用引用?這裏須要簡單介紹2種方法:引用計數法和可達性分析算法;

  這裏簡單說一下引用計數法:對象中添加一個引用計數器,每當有一個地方引用計數器就增長1,引用失效就減小1,計數器爲0就不可用;缺點就在於沒法處理對象直接相互引用的問題,由於相互引用之後沒法使計數器爲0,因此沒法回收;

  可達性分析算法,也就是咱們常說的GC Root,,當一個對象沒有與任何引用鏈相連的時候,就能夠對該對象進行回收,下面是Java中GC Root對象使用的幾個地方:

 

  

   以上對象簡單就是分爲可用和不可用這2種,如今Java對引用概念進行擴充:

  明白這些咱們基本明白JVM如何正確回收,接下來就是JVM什麼狀況下觸發GC以及GC觸發的方式?

  第一個問題比較容易回答固然是當內存空間不足的時候就須要觸發GC,GC回收的時候採用的是分代收集的算法,主要分爲年輕代和老年代,接下來咱們簡單介紹一下這2種方式:

   年輕代:當一個對象被建立的時候,內存分配首先分配在年輕代,大部分對象建立之後都再也不使用,對象很快變得不可達,就是對象無用,因爲垃圾是被年輕代清理掉的,因此被叫作Minor GC或者Young GC。

   老年代:對象若是在年輕代存活了足夠長的時間而沒有被清理掉(即在幾回Young GC後存活了下來),則會被複制到年老代,年老代的空間通常比年輕代大,能存放更多的對象,在年老代上發生的GC次數也比年輕代少。當年老代內存不足時,將執行Major GC,也叫 Full GC。

   明白這2塊主要存放什麼東西之後接下來咱們看下GC的總體結構,看一個對象如何被Kill掉的流程:

   

   1.當一個對象被建立的時候(new)首先會在年輕代的Eden區被建立,直到當GC的時候,根據可達性算法,看一個對象是否消亡,沒有消亡的對象會被放入年輕帶的Survivor區,消亡的直接被Minor GC Kill掉;

   2.進入到Survivor區的對象也不是安全的,當下一次Minor GC來的時候仍是會檢查Enden和Survivor存放對象區域中對象是否存活,存活放入另一塊Survivor區域;

   3.當2個Survivor區切換幾回之後,會直接進入老年代,固然進入到老年代也不是安全的,當老年代內存空間不足的時候,會觸發Major GC,已經消亡的依然仍是被Kill掉;

   推薦一個這個寫的很逗能夠看下:http://blog.csdn.net/sd4015700/article/details/50109939

   接下來咱們還須要說一下GC的算法:標記--清除,複製,標記--整理這3種算法;

   

 

   

 

 

   瞭解算法和GC內存分佈之後咱們接下來介紹垃圾回收器,這部份內容我不計劃用文字去介紹,在第三個欄目我會將我對《深刻理解Java虛擬機》這本書的思惟導圖,內容還不是很完善我正在整理中,可是有GC這部份內容包括各類參數配置,你們能夠下載下來具體瞭解一下;

    最後咱們談一下監控和優化,當年具有以上知識之後這些都將不是問題,因此工欲善其事必先利其器,這就是我要說的,剩下就是對工具操做,這些我認爲不須要介紹也是能夠的,固然我也推薦一個博客:http://blog.csdn.net/renfufei/article/details/56678064

3、結束語

    思惟導圖工具:XMind

    百度雲盤地址:連接:https://pan.baidu.com/s/1ge3eE2Z 密碼:hox4 這部分我尚未完善全,正在努力中,應該大概須要1周左右的時間;若是沒有百度雲盤能夠加入我QQ羣:438836709,能夠一塊兒溝通學習Java的經驗,羣裏面我也分享不少PDF的書籍,反正歡迎你們加入吧!固然我也會把這個文件完善之後上傳到QQ羣裏面!!

相關文章
相關標籤/搜索