天天看點

深入了解Java虛拟機(1)記憶體模型

虛拟機記憶體模型總結

先來一個總結:

記憶體區域 說明
程式計數器 目前線程執行的位元組碼行号計數器
本地方法棧 native方法棧
java虛拟機棧 執行java方法時的記憶體模型,65535
Java堆 存放對象執行個體,數組,存類的屬性值,不存方法
方法區 堆的邏輯部分:類資訊,常量,靜态變量,jit 編譯後的代碼
運作時常量池 存放編譯期間生成的各種字元串和符号引用
直接記憶體 不屬于虛拟機的部分,屬于作業系統記憶體

一.程式計數器

程式計數器是一塊較小的記憶體,他可以看做是目前線程所執行的行号訓示器,位元組碼解釋器工作的時候就是通過改變這個計數器的值來選取下一條需要執行的位元組碼的指令,分支、循環、跳轉、異常處理、線程恢複等基礎功能都需要依賴這個計數器來完成。

當線程執行java方法,則記錄正在執行的虛拟機位元組碼指令位址,

當執行native方法,記錄的值為空(undefined)。

注意點:

  • 線程私有!!!,一個線程一個程式計數器
  • 此記憶體區域是唯一 一個在Java虛拟機規範中沒有規定任何OutOfMemoryError情況的區域。

二.Java虛拟機棧

虛拟機棧是java方法的記憶體模型:每個方法在執行的同時都會建立一個棧幀用于儲存局部變量表、操作數棧、動态連結、方法出口等資訊。每個方法從調用直至完成的過程,就對應着一個棧幀在虛拟機棧中入棧到出棧的過程。

棧記憶體就是虛拟機棧,或者說是虛拟機棧中局部變量表的部分。局部變量表存放了編輯期可知的各種基本資料類型(boolean、byte、char、short、int、long、double、float)、對象引用(reference)類型和returnAddress類型(指向了一條位元組碼指令的位址)

注意點:

  • 局部變量表所需的記憶體空間在編譯期間完成配置設定,所占記憶體大小被提前确定—這是能移動指針執行方法的基礎
  • 棧記憶體屬于單個線程,每個線程都會有一個棧記憶體
  • 線程請求棧的深度大于虛拟機棧所允許的深度,這時候将會抛出StackOverflowError異常,
  • 如果當Java虛拟機允許動态擴充虛拟機棧的時候,當擴充的時候沒辦法配置設定到記憶體的時候就會報OutOfMemoryError異常

三.本地方法棧

與虛拟基棧類似,用來執行native方法

  •   本地方法棧區域也會抛出StackOverflowError和OutOfMemoryError異常。

四.Java堆

堆是Java虛拟機所管理的記憶體中最大的一塊。Java堆是被所有線程共享的一塊記憶體區域,在虛拟機啟動的時候建立,此記憶體區域的唯一目的是存放對象執行個體,幾乎所有的對象執行個體都在這裡配置設定記憶體。

Java堆是GC管理的主要區域。

  • Java堆可以處于實體上不連續的記憶體空間中,隻要邏輯上連續是連續的即可。
  • 若在堆中沒有完成執行個體配置設定,并且堆也無法再擴充時,将會抛出OutOfMemoryError異常。

五.方法區Non-Heap

  方法區用于儲存已被虛拟機加載的類資訊、常量、靜态變量、即時編譯器編譯後的代碼等資料。

六.運作時常量池:

它是方法區的一部分。class檔案中除了有關的版本、字段、方法、接口等描述資訊外、還有一項資訊是常量池,用于存放編輯期生成的各種字面量和符号引用,這部分内容将在類加載後進入方法區的運作時常量池中存放。

  •   當常量池無法再申請到記憶體時會抛出OutOfMemoryError異常。

七.直接記憶體:

Java1.2 版本出現的NIO子產品提供的功能,可以使用native函數庫直接配置設定堆外記憶體,通過DirectByteBuffer對象引用來操作記憶體,不受虛拟機記憶體限制,受本機記憶體限制