JVM內存區域劃分及其管理機制

    java 虛擬機在執行java程序的過程當中會把它所管理的內存劃分爲若干個不一樣的數據區域,如圖。各個區域有各自的用途,以及建立時間和銷燬時間,有的區域隨着虛擬機進程啓動而存在,有些區域則依賴用戶線程的啓動和結束而創建和銷燬。
java

  • 程序計數器:是一塊較小的內存空間,它的做用能夠看作是當前線程所執行的字節碼的行號指示器。在虛擬機的概念模型裏(僅是概念模型,各類虛擬機可能會經過一些更高效的方式去實現),字 節碼解釋器工做時就是經過改變這個計數器的值來選取下一條須要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都須要依賴這個計數器來 完成。程序員

    因爲Java虛擬機的多線程是經過線程輪流切換並分配處理器執行時間的方式來實現的,在任何一個肯定的時刻,一個處理器(對於多核處理器來講是 一個內核)只會執行一條線程中的指令。所以,爲了線程切換後能恢復到正確的執行位置,每條線程都須要有一個獨立的程序計數器,各條線程之間的計數器互不影 響,獨立存儲,咱們稱這類內存區域爲「線程私有」的內存。數組

    若是線程正在執行的是一個Java方法,這個計數器記錄的是正在執行的虛擬機字節碼指令的地址;若是正在執行的是Natvie方法,這個計數器 值則爲空(Undefined)。此內存區域是惟一一個在Java虛擬機規範中沒有規定任何OutOfMemoryError狀況的區域。安全

  • 方法區:在類裝載器加載class文件到內存的過程當中,虛擬機會提取其中的類型信息,並將這些信息存儲到方法區。方法區用於存儲已被虛擬機加載的類信息、常量、靜 態變量、即時編譯器編譯後的代碼等數據。因爲全部線程都共享方法區,所以它們對方法區數據的訪問必須被設計爲是線程安全的。。在JVM規範中,沒有強制要求方法區必須實現垃圾回收。不少人習慣將方法區稱爲「永久代」,是由於HotSpot虛擬機以永久代來實現方法區,從而JVM的垃圾收集器能夠像管理堆區同樣管理這部分區域,從而不須要專門爲這部分設計垃圾回收機制。垃圾回收器在回收的時候,也僅僅針對常量池和對類型的回收。不過自從JDK7以後,Hotspot虛擬機便將運行時常量池從永久代移除了。數據結構

  • java堆:用於存儲java程序建立的對象實例及數組,被全部線程共享,在虛擬機啓動時建立,也是垃圾收集器管理的最主要區域,也稱GC堆。多線程

  • java棧:線程私有,生命週期與線程相同。Java棧也稱做虛擬機棧(Java Vitual Machine Stack),也就是咱們經常所說的棧,跟C語言的數據段中的棧相似。事實上,Java棧是Java方法執行的內存模型。爲何這麼說呢?下面就來解釋一下其中的緣由。spa

    Java棧中存放的是一個個的棧幀,每一個棧幀對應一個被調用的方法,在棧幀中包括局部變量表(Local Variables)、操做數棧(Operand Stack)、指向當前方法所屬的類的運行時常量池(運行時常量池的概念在方法區部分會談到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些額外的附加信息。當線程執行一個方法時,就會隨之建立一個對應的棧幀,並將創建的棧幀壓棧。當方法執行完畢以後,便會將棧幀出棧。 所以可知,線程當前執行的方法所對應的棧幀一定位於Java棧的頂部。講到這裏,你們就應該會明白爲何 在 使用 遞歸方法的時候容易致使棧內存溢出的現象了以及爲何棧區的空間不用程序員去管理了(固然在Java中,程序員基本不用關係到內存分配和釋放的事情,由於 Java有本身的垃圾回收機制),這部分空間的分配和釋放都是由系統自動實施的。對於全部的程序設計語言來講,棧這部分空間對程序員來講是不透明的。下圖 表示了一個Java棧的模型:線程

    局部變量表,是指存放了編譯期間可知的各類基本數據類型(boolean、byte、char、short、int、float、long、double)、對象引用(reference類型)和returnAddress類型(指向了一條字節碼指令的地址)。其中64位長度的long和double類型的數據會佔用2個局部變量的空間,其餘的只佔用1個。局部變量表所需的空間是在編譯時完成分配的,當進入一個方法時,這個方法在幀中分配多大的局部變量空間是徹底肯定的,所以,在方法運行期間不會改變局部變量表的大小。設計

    操 做數棧,想必學過數據結構中的棧的朋友想必對錶達式求值問題不會陌生,棧最典型的一個應用就是用來對錶達式求值。想一想一個線程執行方法的過程當中,實際上就 是不斷執行語句的過程,而歸根到底就是進行計算的過程。所以能夠這麼說,程序中的全部計算過程都是在藉助於操做數棧來完成的。
    對象

    指向運行時常量池的引用,由於在方法執行的過程當中有可能須要用到類中的常量,因此必需要有一個引用指向運行時常量。

    方法返回地址,當一個方法執行完畢以後,要返回以前調用它的地方,所以在棧幀中必須保存一個方法返回地址。

    因爲每一個線程正在執行的方法可能不一樣,所以每一個線程都會有一個本身的Java棧,互不干擾。

  • 本地方法棧:本地方法棧與Java棧的做用和原理很是類似。區別只不過是Java棧是爲執行Java方法服務的,而本地方法棧則是爲執行本地方法(Native Method)服務的。在JVM規範中,並無對本地方發展的具體實現方法以及數據結構做強制規定,虛擬機能夠自由實現它。在HotSopt虛擬機中直接就把本地方法棧和Java棧合二爲一。

  • 運行時常量池:是方法區的一部分。Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項常量池,用於存放編譯期生成的各類字面量和符號引用。

相關文章
相關標籤/搜索