Java內存區域

  轉載請註明源出處:http://www.cnblogs.com/lighten/p/5971424.htmlhtml

1.前言

  Java因爲有自動內存管理機制,因此開發人員通常不須要擔心內存泄漏等問題。可是這不意味着內存問題不會發生,因爲不關注內存相關的問題,使得查找這方面的問題顯得異常困難,因此瞭解虛擬機是如何使用內存是十分有必要的,還能夠加深本身對程序的理解。全部JVM系列的內容都是閱讀《深刻理解JAVA虛擬機》和《Java Virtual Machine Specification》,提煉歸納的,因爲書的出版年限較早,當時JDK8尚未出來,這版還只是基於JDK7,本人功力尚淺,處於學習階段,目前JDK9在測試之中。這段期間JVM技術也在發展,可能有些內容與目前的技術有所出入,固然變更也不太可能很大,不過閱讀的時候要注意這個問題,若是有什麼地方目前版本改進了,請指教,謝謝。數組

2.內存區域劃分

2.1 JDK7

  Java虛擬機定義了一些程序在運行期間會使用到的運行時數據區,其中有一些會隨着虛擬機的啓動時建立,退出時銷燬,另外一些數據區域與線程對應,線程開始和結束會致使其對應的數據區域建立和銷燬。多線程

  紅色指的是線程獨立或稱之爲線程私有的內存,藍色就是線程共享的區域了。函數

  1)PC寄存器(程序計數器)Java虛擬機支持多線程,每個虛擬機線程都有本身的PC(Program Counter)寄存器。在任什麼時候刻,一條Java虛擬機的線程只會執行一個方法的代碼,這個正在被執行的方法稱之爲當前方法(Current Method)。若是這個方法不是native的,那麼PC寄存器就會保存正在執行的字節碼指令的地址,若是該方法是native的,那PC寄存器的值是undefined。PC寄存器的容量至少應當能保存一個returnAddress類型的數據或者一個與平臺相關的本地指針的值。這是JAVA虛擬機規範之中惟一一個沒有規定任何OutOfMemoryError狀況的區域。性能

  2)Java虛擬機棧:Java中每個線程都有本身私有的Java虛擬機棧(Java Virtual Machine Stack),這個棧與線程同時建立,用於存儲棧幀(Frames)。其做用與傳統語音(C語言等)中的棧很是相似,就是用於存儲局部變量和一些過程結果的地方。其存儲局部變量表、操做數棧、動態連接、方法出口等信息。每個方法從調用到執行完成的過程,就對應着一個棧幀在虛擬機中入棧到出棧的過程。Java虛擬機棧可能有以下異常狀況:1.若是線程請求分配的棧容量超過Java虛擬機容許的最大容量時,會拋出一個StackOverflowError異常。2.若是Java虛擬機棧能夠動態擴展,而且擴展的動做已經嘗試過,可是目前沒有申請到足夠的內存去完成擴展,或者在創建新的線程時沒有足夠的內存去建立對應的虛擬機棧,那Java虛擬機將會拋出一個OutOfMemoryError異常。學習

  3)本地方法棧:Java虛擬機實現可能會使用到傳統的棧(一般稱爲‘C Stacks’)來支持native方法(指Java之外的其餘語言編寫方法)的執行,這個棧就是本地方法棧了(Native Method Stack)。當虛擬機使用其餘語言來實現指令集解釋器時,也會使用到本地方法棧。若是Java虛擬機不支持native方法,而且本身也不依賴傳統棧,能夠無需支持本地方法棧,若是支持本地方法棧,那這個棧通常會在線程建立的時候按線程分配。本地方法棧可能有以下異常狀況:若是線程請求分配的棧容量超過本地方法棧容許的最大容量時,Java虛擬機將會拋出一個StackOverflowError異常。若是本地方法棧能夠動態擴展,而且擴展動做已經嘗試過,可是目前的沒法申請到足夠的內存去完成擴展,或者在創建新的線程時沒有足夠的內存去建立對應的本地方法棧,那Java虛擬機將會拋出一個OutOfMemoryError異常。測試

  4)Java堆:在Java虛擬機中,堆(Heap)是能夠供各條線程共享的運行時內存區域,也是供全部類實例和數組對象分配內存的區域。堆在虛擬機啓動的時候就被建立了,它存儲了被自動內存管理系統(Automatic Storage Management System,也就是常說的「Garbage Collector(垃圾收集器)")所管理的各類對象,這些受管理的對象無需,也沒法顯式地被銷燬。在實現時,能夠是固定大小,也能夠是可擴展的(經過-Xmx和-Xms控制)。若是實際所需的堆超過了自動內存管理系統能提供的最大容量,那Java虛擬機將會拋出一個OutOfMemoryError異常。spa

  5)方法區:在虛擬機中,方法區(Method Area)是可供各個線程共享的運行時內存區域。方法區與傳統語言中的編譯代碼儲存區(Storage Area Of Compiled Code)或操做系統進程的正文段(Text Segment)的做用很是相似,它存儲了每個類的結構信息,例如運行時常量池(Runtime Constant Pool)、字段和方法數據、構造函數和普通方法的字節碼內容,還包括一些在類、實例、接口初始化時用到的特殊方法。方法區在虛擬機啓動的時候被建立,雖然方法區是堆的邏輯組成部分,可是簡單的虛擬機實現能夠選擇在這個區域不實現垃圾收集。這個版本的Java虛擬機規範也不限定實現方法區的內存位置和編譯代碼的管理策略。若是方法區的內存空間不能知足內存分配請求,那Java虛擬機將拋出一個OutOfMemoryError異常。操作系統

  6)運行時常量池:Runtime Constant Pool是每個類或者接口的常量池的運行時表示形式,它包括了若干種不一樣的常量:從編譯期可知的數值字面量到必須運行時解析後才能得到的方法或字段引用。運行時常量池扮演了相似傳統語言中符號表(Symbol Table)的角色,不過它存儲數據範圍比一般意義上的符號表更爲普遍。每個運行時常量池都分配在Java虛擬機的方法區中,在類和接口被加載到虛擬機後,對應的運行常量池就被建立出來。當建立類或接口的時候,若是構造運行時常量池所須要的內存空間超過了方法區所能提供的最大值,那Java虛擬機將會拋出一個OutOfMemoryError異常。線程

  7)直接內存:直接內存(Direct Memory)並非虛擬機運行時數據區的一部分,也不是Java虛擬機規範中定義的內存區域。可是這部份內存也被頻繁地使用。並且也可能致使OutOfMemoryError異常出現。在JDK1.4中新加入了NIO(New Input/Output)類,引入了一種基於通道(Channel)與緩衝區(Buffer)的I/O方式,它可使用native函數庫直接分配堆外內存,而後經過一個存儲在Java堆中的DirectByteBuffer對象做爲這塊內存的引用來操做。這樣能在一些場景中顯著提升性能,由於避免了在Java堆和Native堆中來回複製數據。各個區域總內存(包括直接內存)要小於物理內存。

2.2 JDK8

  看了一下JDK8的Java虛擬機規範,貌似沒有太大的改變。

3 結束語

  前面五個區域大體就是JVM的內存劃分了,咱們最須要關注的是堆和Java虛擬機棧,一個保持着對象實例,一個是方法的執行數據,下一章會講一下棧幀的結構,更方便理解方法是如何調用的。

相關文章
相關標籤/搜索