C和C++工程師掌握創建和銷毀記憶體空間的權力,并維護記憶體中每一個物件從始至終的生命,但Java工程師可以不再繁瑣的進行記憶體控制,并且更不容易出現記憶體泄露和溢位的問題,但如果不了解Java是如何自動對記憶體進行控制的,在出現問題后更難定位,
JVM記憶體運行時資料區域
JVM運行時會將所管轄的記憶體劃分為不同區域做不同功能,有的隨虛擬機行程而生死,有的因執行緒而生死,虛擬機規范規定記憶體中要包含以下幾個區域:

-
程式計數器:較小空間的記憶體,用于記錄當前執行緒所執行的位元組碼檔案所在行號,通過改變這里的行號來實作指令中的分支、回圈、跳轉等操作,因為Java的多執行緒是多個執行緒輪流切換運行的,在執行另一執行緒時要讓來源執行緒記錄好自己所處的行號,所以每個執行緒都有自己獨立的程式計數器,相互之間不會干擾,這種每個執行緒獨有的空間就叫執行緒私有空間,當執行的是Natvie方法時,此空間記錄為空,并且此空間是唯一不存在記憶體溢位錯誤的空間,
-
堆疊:執行緒私有且生命周期與執行緒相同,在執行每個方法時都會創建堆疊幀壓入到堆疊里,方法的呼叫開始就是堆疊幀入堆疊,完成就是堆疊幀出堆疊,堆疊幀中記錄著方法的區域變數表、操作堆疊、動態鏈接和方法出口等資訊,區域變數表存放了編譯期間可知的基本型別和參考型別,還有就是returnAddress型別,表示一條位元組碼指令的地址,其中64位長度的變數資料將占用兩個變數空間,其余占用一個變數空間,區域變數表會在編譯期間完成分配,當進入一個方法開始指向的時候,這個方法所需要的區域記憶體就已經確定了,不會再改變了,當方法呼叫深度過深,比如出現了自呼叫情況時,就會出現堆疊溢位例外,當然一些虛擬機堆疊會動態擴大堆疊深度,當無法再獲取記憶體資源來擴展時會出現記憶體溢位例外,
-
本地方法堆疊:跟虛擬機堆疊很類似,采用同樣的存盤方式也會有同樣的例外,但是用來運行Native方法的,沒有規定其中方法所使用的語言,所以可以自由的實作它,有的虛擬機例如HotSpot,就把虛擬機堆疊和本地方法堆疊合二為一了,
-
堆:堆是JVM中最大的空間,是所有執行緒都會共享的空間,將在虛擬機啟動時創建,也就是與行程同生死,對里存放物件的實體,所有的物件實體都將在這里進行分配,垃圾回收也將主要在堆中執行,為了更快的回識訓會把堆中的物件進行各種分類,堆是物理不連續的記憶體空間,只要邏輯上是連續的就可以,這類似磁盤空間,當堆沒法再去獲得空間將出現記憶體溢位例外,
-
方法區:存盤被虛擬機加載的類資訊、常量、靜態變數、即時編譯器編譯后的代碼等,是執行緒共享的,雖然Java規范將其形容為堆的一個區域,但只是一個邏輯磁區,HotSpot虛擬機把方法區在垃圾回收中設定為永生代,但其他的虛擬機并不存在永生代的說法,之所以這么叫是因為其中的內容很少會被清理,清理起來也是比較的麻煩,Java官方Bug清單中就出現了很多因為此處空間導致的記憶體泄露,它像堆一樣是不連續的物理記憶體,可以固定或擴展大小,可以選擇不實作垃圾回收,當無法獲取記憶體時也會出現記憶體溢位例外,
-
運行時常量池:它是方法區的一部分,Class檔案中除了類的版本、欄位、方法、介面等描述資訊外還有就是常量池,用于存放編譯期間生成的字面量和符號參考,在類加載后放入此處空間,JVM對Class檔案的每個部分都做了嚴格的規定,每個位元組存盤哪種資料都必須規范才會被JVM認可、裝載和執行,但對于常量池JVM規范并沒有特殊要求,不同的提供商可以自己實作這塊區域,所以通常除了存放字面量和符號參考外,直接參考也會存在這里,Class檔案常量池必須具備動態性,也就是并不一定在編譯期間產生,運行時也可以放入新的常量,因為是方法區的一部分,所以當空間無法擴展也會出現記憶體溢位例外,
-
直接記憶體:并不是JVM運行時記憶體的一部分,并且也并未在JVM規范中定義,但這塊記憶體也被頻繁使用并且也會出現記憶體溢位例外,JDK1.4中引入了NIO,非阻塞的IO方式,可以讓Native函式直接分配堆外的記憶體,然后通過堆里的DirectByteBuffer物件作為參考指向這款記憶體,從而避免在堆和Native堆中切換復制資料,從而提高性能,堆外記憶體實在本機記憶體中的,雖然不會收到JVM的影響但空間和尋址空間的限制,當記憶體區域大于物理記憶體限制的時候會導致記憶體溢位例外,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/325263.html
標籤:其他
