言簡意賅——總結Java內存區域和常量池

Java內存區域和常量池的總結

本文用最簡潔的描述,來總結出Java內存區域和常量池的相關知識,如需更加深刻學習Java內存區域以及常量池,可參考閱讀《深刻Java虛擬機》或者網上優秀博文。java

運行時數據區

運行數據區包含如下幾個區域:數組

  1. 方法區(Method Area)
  2. Java堆(Heap)
  3. 本地方法棧(Native Method Stack)
  4. 虛擬機棧(VM Stack)
  5. 程序計數器(Program Conter Register)

其中方法區和堆是全部線程共享的數據區,而其餘三個區收拾線程隔離的數據區。數據結構

Java虛擬機在執行Java程序的過程當中將它管理的內存劃分爲若干個不一樣的區域,這些區域都擁有各自的用途以及建立和銷燬的時間。函數

方法區和堆都是依賴虛擬機線程的啓動而建立;本地方法棧、虛擬機棧和程序計數器都依賴用戶線程的啓動和結束而創建和銷燬。學習

image

程序計數器spa

  1. 該區是一塊較小的內存空間。
  2. 能夠看做是字節碼的行號指示器。
  3. 分支、循環、跳轉、異常處理、線程恢復等基礎工做都是基於程序計數器來完成的,由於字節碼解釋器工做的時候,就是根據程序計數器的值來確認下一條須要執行的字節碼子令。
  4. 該區是線程獨立的,被稱爲「線程私有」的內存。
  5. 該區域是惟一一個在Java虛擬機規範中沒有規定任何OOM(OutOfMemoryError)狀況的區域。

Java虛擬機棧線程

  1. 該區是線程私有的。
  2. Java虛擬機棧描述的是Java方法的內存模型。
  3. 該區就是所謂的「棧內存」,實際上Java內存不可粗糙的分爲堆內存和棧內存,由於Java內存區域的劃分比這複雜的多。
  4. 該區會拋出StackOverflowError異常和OOM(OutOfMemoryError)異常;當線程請求的棧深度大於虛擬機所容許的深度時,會拋出棧溢出異常。由於虛擬機棧是能夠動態擴展的,因此當虛擬機棧沒法申請到足夠的內存時,就會拋出OOM異常。

關於Java方法的內存模型指針

每一個Java方法在執行的同時,都會建立一個棧幀存放於棧中,而該棧幀中會存儲局部變量表、操做數棧、動態鏈接、方法出口等信息。當方法結束調用,棧幀就會出棧。cdn

局部變量表對象

局部變量表存放:

  1. 編譯期可知的基本數據類型(boolean、char、byte、short、long、flag、int、double)。
  2. 對象引用。
  3. returnAddress(指向一條字節碼指令的地址)。

對於局部變量表,須要注意:

  1. 局部變量表所需的內存空間在編譯期就已經完成分配了,當進入一個方法時這個方法須要在棧幀中分配多大的局部變量空間是徹底肯定的,在方法運行期間不能改變局部變量表的大小。

本地方法棧

  1. 本地方法棧使用到的是Native方法服務,基本的原理和Java虛擬機棧很是類似。
  2. Sun HotSpot將本地方法棧和Java虛擬機棧合二爲一。
  3. 本地方法棧也會拋出StackOverflowErrot和OOM異常。

Java堆

  1. Java堆是虛擬機所管理的內存中最大的一塊。而且是線程共享的,隨着虛擬機線程的啓動而創建。
  2. 此區域的惟一目的就是存儲對象,幾乎全部的實例對象都在該區分配內存,爲何不是所有呢?由於一個類的java.lang.Object類對象是在方法區中分配內存的。
  3. 幾乎全部的對象實例以及數組都要在堆上分配內存。
  4. 此區是垃圾收集器管理的主要區域,因此此區也被稱爲GC堆。
  5. Java堆可分爲新生代、老年代,新生代又可細分爲Eden空間、From Survivor空間、To Survivor空間。
  6. 堆內存中的區域是物理上不連續的,但邏輯上是連續的內存區域。
  7. 此區域可拓展,也可固定,通常都是定爲可拓展(經過-Xmx和-Xms控制)。
  8. 堆中若是沒有內存分配給實例,而且沒法再拓展內存區域了,就會拋出OOM異常。

方法區

  1. 方法區是線程共享的區域。
  2. 方法區存儲虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。
  3. 方法區被不少人稱爲「永久代」,由於HotSpot團隊選擇把GC延伸至方法區。不過如今已經有放棄永久代並逐步改成採用Native Memory來實現方法區的規劃了,在JDK1.7的HotSpot中,一把本來放在永久代中的字符串常量池移出。
  4. 內存區域能夠是物理上不連續的,但邏輯上是連續的,與堆內存是一致的。
  5. 方法區由於老是存放不會輕易改變的內容,故又被稱之爲「永久代」。HotSpot也選擇把GC分代收集擴展至方法區,但也容易遇到內存溢出問題。能夠選擇不實現垃圾回收,但若是回收就主要涉及常量池的回收和類的卸載。
  6. 該區域沒法知足內存分配需求時,會拋出OOM異常。

非運行時數據區——直接內存

  1. 直接內存不是運行時數據區的一部分,並非Java定義規範中的內存區域,可是不合理的使用也會致使OOM異常。
  2. JDK 1.4中新加入了NIO類,引入了一種基於通道(Channel)與緩衝區(Buffer)的I/O方式,它可使用Native函數庫直接分配堆外內存,而後經過一個存儲再Java堆中的DirectByteBuffer對象做爲這塊內存的引用進行操做。

運行時常量池?靜態常量池(class文件常量池)?字符串常量池?有什麼區別?下面一去來看看這個讓人容易混淆的三個概念。

Java中的常量池

class文件常量池

咱們都知道,class文件中除了包含類的版本、字段、方法、接口等描述信息外,還有一項信息就是常量池(constant pool table),用於存放編譯器生成的各類字面量(Literal)和符號引用(Symbolic References),這就是咱們所說的class文件常量池。 字面量就是咱們所說的常量概念,如文本字符串、被聲明爲final的常量值等。 符號引用是一組符號來描述所引用的目標,符號能夠是任何形式的字面量,只要使用時能無歧義地定位到目標便可(它與直接引用區分一下,直接引用通常是指向方法區的本地指針,相對偏移量或是一個能間接定位到目標的句柄)。通常包括下面三類常量:

  • 類和接口的全限定名
  • 字段的名稱和描述符
  • 方法的名稱和描述符

(每種常量類型的數據結構能夠查看《深刻理解java虛擬機》第六章的內容)

  1. class常量池是在編譯的時候每一個class都有的,在編譯階段,存放的是常量的符號引用。

運行時常量池

  1. 運行時常量池是方法區中的一部分。
  2. Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有常量池(Constant Pool Table)。
  3. 常量池中存儲的是編譯期生成的各類字面量和符號引用,在JDK1.6及其以前的版本,這部份內容都將在類加載完後進入到方法區的運行時常量池中存放。
  4. 運行時常量池相比於類常量池的不一樣特徵在於,運行時常量池具有動態性,也就是說不必定要編譯期的時候才能產生常量,也能夠在運行時產生常量,好比在運行期間調用String.intern()方法,也能夠將新的常量放入運行時常量池中。
  5. 運行時常量池是在類加載完成以後,將每一個class常量池中的符號引用值轉存到運行時常量池中,也就是說,每一個class都有一個運行時常量池,類在解析以後,將符號引用替換成直接引用,與全局常量池中的引用值保持一致。

string.intern()做用:

檢查字符串常量池中是否存在String並返回池裏的字符串引用;若池中不存在,則將其加入池中,並返回其引用。 這樣作主要是爲了不在堆中不斷地建立新的字符串對象。

字符串常量池

  1. 字符串常量池在每一個VM中只有一份,存放的是字符串常量的引用值。
  2. 字符串常量池——string pool,也叫作string literal pool。
  3. 字符串池裏的內容是在類加載完成,通過驗證,準備階段以後在堆中生成字符串對象實例,而後將該字符串對象實例的引用值存到string pool中。
  4. string pool中存的是引用值而不是具體的實例對象,具體的實例對象是在堆中開闢的一塊空間存放的。

對於string pool:

在HotSpot VM裏實現的string pool功能的是一個StringTable類,它是一個哈希表,裏面存的是駐留字符串(也就是咱們常說的用雙引號括起來的)的引用(而不是駐留字符串實例自己),也就是說在堆中的某些字符串實例被這個StringTable引用以後就等同被賦予了」駐留字符串」的身份。這個StringTable在每一個HotSpot VM的實例只有一份,被全部的類共享。

JDK不一樣版本與常量池位置的變化

  1. 在JDK1.6版本之前,運行時常量池在方法區中;JDK1.7版本是,運行時常量池是在堆中;JDK1.8時,運行時常量池是在方法區和堆區相對獨立的元空間(Metaspace),而不是在堆區。
  2. 不一樣版本由於OOM致使的問題: JDK1.6版本——java.lang.OutOfMemoryError: PermGen space; JDK1.7版本——java.lang.OutOfMemoryError:Java heap space; JDK1.8版本——java.lang.OutOfMemoryError: Metaspace;
相關文章
相關標籤/搜索