談談對JVM的理解

        JVM可謂是學習JAVA基礎中的基礎了,但仍有很多同窗對JVM概念仍是比較模糊,甚至沒有據說過,對java的理解也只是在基礎語法 層面,本文就將對JVM進行初步介紹,因篇幅所限,只能介紹JVM基礎,如須要進一步學習,建議閱讀機械工業出版社出版的《深刻理解JAVA虛擬機》。

        請尊重做者勞動成果,轉載請標明原文連接:html

   http://www.javashuo.com/article/p-cxaoypfi-mm.htmljava

        Java虛擬機規範中規定的JVM以下圖所示:
        能夠看出,JVM由JVM運行時數據區(圖示中藍色框包含部分)、執行引擎、本地庫接口、本地方法庫組成。
 
        JVM運行時數據區,分爲線程共享部分(方法區、堆)和線程隔離區(虛擬機棧、本地方法棧和程序計數器)。
        1.方法區
         用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。
        運行時常量池(Runtime Constant Pool)是方法區的一部分。.Class文件中除了有類的版本/字段/方法/接口等描述信息外,還有一項信息是常量池(Constant Pool Table),用於存放編譯期生成的各類字面量和符號引用,這部份內容將類在加載後進入方法區的運行時常量池中存放.
運行時常量區的內容並不僅是在編譯期間產生,經過String.intern()也能夠實如今運行時向常量區中添加內容。
        須要注意的是:從JDK8開始,方法區被元數據區替代了。具體的緣由和二者的區別能夠參考官網。
 
        2.堆
        是JVM中最大的一塊內存區域,該區域的目的只是用於存儲對象實例及數組。該區域也是GC的最主要區域。
        根據Java虛擬機規範的規定,Java堆能夠處於物理上不連續的內存空間中,只要邏輯上是連續的便可,就像咱們的磁盤空間同樣.在實現時,既能夠實現固定大小的,也能夠是可擴展的,不過當前主流的虛擬機都是按照可擴展來實現的(經過-Xmx和-Xms控制).若是在堆中沒有內存完成實例分配,而且堆也沒法再擴展時,就會拋出OutOfMemoryError異常。
 
        3.虛擬機棧
        每一個線程方法在執行時都會建立一個棧幀,包含局部變量表、返回地址、操做數棧等信息。每一個方法的執行與完成就對應的棧幀的入棧與出棧過程 。局部變量表佔用空間的大小在編譯期就肯定了。這裏須要注意:若是線程請求的棧深度大於虛擬機所容許的深度,將會拋出StackOverflowError異常;若是虛擬機棧能夠動態擴展(當前大部分的Java虛擬機均可動態擴展,只不過Java虛擬機規範中也容許固定長度的虛擬機棧),當擴展時沒法申請到足夠的內存時將會拋出OutOfMemoryError異常。
 
        4.本地方法棧
        與虛擬機棧相似,不過其中執行是本地方法。對於HotSpot虛擬機而言,本地方法棧和虛擬機棧是統一的。
 
        5.程序計數器
       是一個小的內存空間,若是線程正在執行的是一個java方法,則此內存區域記錄正在執行的虛擬機字節碼指令的地址;若是線程正在執行的是native方法,則計算器中的值爲空。此內存區域是惟一一個在JAVA虛擬機規範中沒有規定任何OutOfMemoryError狀況的區域。
 
        這幾部分都有相關的JDK自帶工具能夠分析查看,好比jps, jstack, jmap, jhat, jstat等,還有圖形化工具jconsole,jvisualvm,但對於Linux服務器就無能爲力了。
 
        好了,關於JVM就講完了,接下來進行提問:JVM哪些區域會發生OOME,以及各自緣由是什麼?
 
        堆內存不足是最多見的 OOM 緣由之一,拋出的錯誤信息是「java.lang.OutOfMemoryError:Java heap space」,緣由可能千奇百怪,例如,可能存在內存泄漏問題;也頗有可能就是堆的大小不合理,好比咱們要處理比較可觀的數據量,可是沒有顯式指定 JVM 堆大小或者指定數值偏小;或者出現 JVM 處理引用不及時,致使堆積起來,內存沒法釋放等。
        而對於 Java 虛擬機棧和本地方法棧,這裏要稍微複雜一點。若是咱們寫一段程序不斷的進行遞歸調用,並且沒有退出條件,就會致使不斷地進行壓棧。相似這種狀況,JVM 實際會拋出 StackOverFlowError;固然,若是 JVM 試圖去擴展棧空間的的時候失敗,則會拋出 OutOfMemoryError。
        對於老版本的 Oracle JDK,由於永久代的大小是有限的,而且 JVM 對永久代垃圾回收(如,常量池回收、卸載再也不須要的類型)很是不積極,因此當咱們不斷添加新類型的時候,永久代出現 OutOfMemoryError 也很是多見,尤爲是在運行時存在大量動態類型生成的場合;相似 Intern 字符串緩存佔用太多空間,也會致使 OOM 問題。對應的異常信息,會標記出來和永久代相關:「java.lang.OutOfMemoryError: PermGen space」。
        隨着元數據區的引入,方法區內存已經再也不那麼窘迫,因此相應的 OOM 有所改觀,出現 OOM,異常信息則變成了:「java.lang.OutOfMemoryError: Metaspace」。
        直接內存不足,也會致使 OOM。
 
        後記:
        JVM是JAVA面試過程當中最容易被問到的基礎題目,在本篇JVM介紹完後,後面還準備了更多有意思的JAVA基礎面試題,這些將做爲提高JAVA基礎能力的免費系列課程,從面試題出發,對每一個問題觸類旁通,以點帶面,不作不求甚解之人,最終目標不是學會答題,而是學會題目自己涉及到的全部知識點。暫定的所有面試題目課程包含以下內容:
        談談你對JVM的理解?
        final,finally,finalize有什麼區別?
        String,StringBuffer,StringBuilder有什麼區別?
        Exception和Error有什麼區別?
        Hashtable,HashMap,TreeMap有什麼區別?
        Vector,ArrayList,LinkedList有什麼區別?
        int和Integer有什麼區別?
        接口和抽象類有什麼區別?
        如何保證集合是線程安全的?
        談談你知道的設計模式?
 
        搜索關注微信公衆號「程序員姜小白」,獲取更新精彩內容哦。
相關文章
相關標籤/搜索