1. 程式人生 > >第一章 JVM記憶體結構

第一章 JVM記憶體結構

注意:本系列部落格,主要參考自以下四本書

《分散式Java應用:基礎與實踐》《深入理解Java虛擬機器(第二版)》《深入分析Java web技術內幕》《實戰java虛擬機器》

1、為什麼要了解JVM記憶體管理機制

  • JVM自動的管理記憶體的分配與回收,這會在不知不覺中浪費很多記憶體,導致JVM花費很多時間去進行垃圾回收(GC)
  • 記憶體洩露,導致JVM記憶體最終不夠用

2、JVM記憶體結構

根據上圖,JVM記憶體結構包括:

  • 方法區(也就是"持久代"),java8裡徹底被移除,取而代之的是元資料區
  • 棧(在hotspot JVM中,JVM方法棧--Java虛擬棧,與本地方法棧是同一個)
  • PC暫存器(程式計數器)

還有一塊:

  • 直接記憶體:直接向系統記憶體申請的一塊記憶體區域,javaNIO會使用,速度優於java堆記憶體。- 隸屬於實體記憶體,不屬於JVM記憶體

注意點:

  • 堆是GC的主要區域,方法區、直接記憶體也會發生GC
  • 棧與PC暫存器是每個執行緒都會建立的私有區域,不會GC
  • 直接記憶體使用速度由於堆記憶體,但是記憶體的申請速度低於堆記憶體

2.1、方法區

  • 存放內容(類的資訊、類static屬性、方法、常量池
    • 已經載入的類的資訊(名稱、修飾符等)
    • 類中的static變數
    • 類中的field資訊
    • 類中定義為final常量
    • 類中的方法資訊
    • 執行時常量池:編譯器生成的各種字面量和符號引用(編譯期)儲存在class檔案的常量池中,這部分內容會在類載入之後進入執行時常量池,class檔案的常量池檢視 第三章 類檔案結構與javap的使用
  • 使用例項:反射,在程式中通過Class物件呼叫getName等方法獲取資訊資料時,這些資訊資料來源於方法區。
  • 調節引數
    • -XX:PermSize:指定方法區的最小值,預設為16M
    • -XX:MaxPermSize:指定方法區的最大值,預設為64M
  • 所拋錯誤
    • 方法區域要使用的記憶體超過了其允許的大小時,丟擲OutOfMemoryError
  • 記憶體回收的主要目標
    • 對類的解除安裝(這也是為什麼很多企業使用velocity等模板引擎做前端而不是使用jsp的原因之一)
    • 針對常量池的回收
  • 總結
    • 一般而言,在企業開發中,-XX:PermSize==-XX:MaxPermSize
    • 通常,這個大小設定為256M就沒問題了,當然還要根據自己的程式去預估,並在執行過程中去調整,這裡以在Resin伺服器中配置為例
                  <jvm-arg>-XX:PermSize=256M</jvm-arg>
                  <jvm-arg>-XX:MaxPermSize=256M</jvm-arg>
      View Code
    •  類中的static變數會在方法區分配記憶體,但是類中的例項變數不會(類中的例項變數會隨著物件例項的建立一起分配在堆中,當然若是基本資料型別的話,會隨著物件的建立直接壓入運算元棧)
    • 關於方法區的存放內容,可以這樣去想所有的通過Class物件可以反射獲取的都是從方法區獲取的(包括Class物件也是方法區的,Class是該類下所有其他資訊的訪問入口)

注意:常量池在jdk1.6在方法區;在jdk1.7在堆

附:元資料區

  • 調節引數:-XX:MaxMetaspaceSize,如果不指定大小,極限情況下可能耗盡系統所有記憶體
  • 元資料區是堆外的一塊直接記憶體

2.2、堆

  • 存放內容
    • 物件例項(類中的例項變數會隨著物件例項的建立一起分配在堆中,當然若是基本資料型別的話,會隨著物件的建立直接壓入運算元棧),這一點檢視 第四章 類載入機制
    • 陣列值
  • 使用例項
    • 所有通過new建立的物件都在這塊兒記憶體分配,具體分配到年輕代還是年老代需要根據配置引數而定(新建物件直接分配到年老代有兩種情況,看下邊)
  • 調節引數
    • -Xmx:最大堆記憶體,預設為實體記憶體的1/4但小於1G
    • -Xms:最小堆記憶體,預設為實體記憶體的1/64但小於1G
    • -XX:MinHeapFreeRatio,預設當空餘堆記憶體小於最小堆記憶體的40%時,堆記憶體增大到-Xmx
    • -XX:MaxHeapFreeRatio,當空餘堆記憶體大於最大堆記憶體的70%時,堆記憶體減小到-Xms
  • 注意點
    • 在實際使用中,-Xmx與-Xms配置成相等的,這樣,堆記憶體就不會頻繁的進行調整了
  • 丟擲錯誤
    • OutOfMemoryError:在堆中沒有記憶體完成例項分配(關於例項記憶體的分配,之後再說),此時堆記憶體已達到最大無法擴充套件時。
  • 堆記憶體劃分

    • 新生代
      • 組成:Eden+From(S0)+To(S1)
      • -Xmn:整個新生代的大小
      • -XX:SurvivorRatio:調整Eden:From(To)的比率,預設為8:1
    • 年老代
      • 新建物件直接分配到年老代,兩種情況
        • 大物件:-XX:PretenureSizeThreshold(單位:位元組)引數來指定大物件的標準,在Parallel Scavenge GC下可能無效,
        • 大陣列:陣列中的元素沒有引用任何外部的物件
  • 總結
    • 企業開發中,-Xmx==-Xms
    • 通常,-Xmx設定為2048m就沒問題了,當然還要根據自己的程式去預估,並在執行過程中去調整,這裡以在Resin伺服器中配置為例
                  <jvm-arg>-Xms2048m</jvm-arg>
                  <jvm-arg>-Xmx2048m</jvm-arg>
                  <jvm-arg>-Xmn512m</jvm-arg>
                  <jvm-arg>-XX:SurvivorRatio=8</jvm-arg>
                  <jvm-arg>-XX:MaxTenuringThreshold=15</jvm-arg>
      View Code

      可以看到,-Xms==-Xmx==2048m,年輕代大小-Xmn==512m,這樣,年老代大小就是2048-512==1536m,這個比率值得記住,在企業開發中,年輕代:年老代==1:3,而此時,我們配置的-XX:MaxTenuringThreshold=15(這也是預設值),年輕代物件經過15次的複製後進入到年老代(關於這一點,在之後的GC機制中會說),

    • -XX:MaxTenuringThreshold與-XX:PretenureSizeThreshold不一樣,不要看錯

2.3、棧

  • 注意點
    • 每條執行緒都會分配一個棧,每個棧中有多個棧幀(每一個方法對應一個棧幀)
    • 執行緒建立的時候建立一個執行緒的java棧
    • 每個方法在執行的同時都會建立一個棧幀,每個棧幀用於儲存當前方法的區域性變量表、運算元棧等,具體檢視本文第一個圖,每一個方法從呼叫直至執行完成的過程,就對應著一個棧幀在虛擬機器棧中入棧到出棧的過程,說的更明白一點,就是方法執行時建立棧幀,方法結束時釋放棧幀所佔記憶體
  • 存放內容
    • 區域性變量表:八大基本資料型別資料、物件引用。該空間在編譯期已經分配好,執行期不變。
    • 運算元棧:是執行引擎直接操作的部分
  • 調節引數
    • -Xss:設定棧的大小,通常設定為1m就好
      <jvm-arg>-Xss1m</jvm-arg>
      View Code
  • 支援native方法執行(本地方法棧)
  • 所拋錯誤
    • StackOverFlowError:執行緒請求的棧深度大於虛擬機器所允許的深度。
      • 棧的深度就是方法呼叫巢狀的層數,受限於-Xss的大小
      • 典型場景:沒有終止條件的遞迴(遞迴基於棧)。
      • 每個方法的棧的深度在javac編譯之後就已經確定了,檢視 第三章 類檔案結構與javap的使用 
    • OutOfMemoryError:虛擬機器棧可以動態擴充套件,如果擴充套件的時候無法申請到足夠的記憶體。
      • 需要注意的是,棧可以動態擴充套件,但是棧中的區域性變量表不可以

2.4、PC暫存器(程式計數器)

  • 概念:當前執行緒所執行的位元組碼的行號指示器,用於位元組碼直譯器對位元組碼指令的執行。
  • 多執行緒:通過執行緒輪流切換並分配處理器執行時間的方式來實現的,在任何一個時刻,一個處理器(也就是一個核)只能執行一條執行緒中的指令,為了執行緒切換後能恢復到正確的執行位置,每條執行緒都要有一個獨立的程式計數器,各條執行緒之間計數器互不影響,獨立儲存。

附:物件分配(《實戰java虛擬機器》)

相關推薦

第一 JVM記憶體結構

注意:本系列部落格,主要參考自以下四本書 《分散式Java應用:基礎與實踐》《深入理解Java虛擬機器(第二版)》《深入分析Java web技術內幕》《實戰java虛擬機器》 1、為什麼要了解JVM記憶體管理機制 JVM自動的管理記憶體的分配與回收,這會在不知不覺中浪費很多記憶體,導致JVM花費很多

第七 JVM體系結構與工作方式

硬件 java內存管理 彈出 操作符 clas 基本 記錄器 pan 操作 JVM能跨計算機體系結構來執行Java字節碼,主要是由於JVM屏蔽了與各個計算機平臺的軟件和硬件之間的差異。 7.1 JVM體系結構   7.1.1 何謂JVM     模擬一個計算機來達到一個計算

JVM記憶體結構、Java記憶體模型以及Java物件模型之間的區別

Java作為一種面向物件的,跨平臺語言,其物件、記憶體等一直是比較難的知識點。而且很多概念的名稱看起來又那麼相似,很多人會傻傻分不清楚。比如本文我們要討論的JVM記憶體結構、Java記憶體模型和Java物件模型,這就是三個截然不同的概念,但是很多人容易弄混。 可以這樣說,很多高階開發甚至都搞

jvm 記憶體結構初步理解

執行緒隔離區 1. 虛擬機器棧:當方法執行時 會建立虛擬棧幀 儲存區域性變量表運算元棧,動態連結和方法出口,而初學者說的’堆疊’指的是棧中棧幀的區域性變量表中的內容,會存放編譯期可知的所有的基本資料型別,和物件型別的引用; 2. 本地方法棧:作用與虛擬機器棧類似,但是是讀取本地方法的; 3.

JVM(一)JVM記憶體結構

Java程式碼需要執行在虛擬機器(JVM)上,而JVM為了方便管理記憶體,會把自己所管理的記憶體劃分為若干個不同的資料區域,用作不同的用途,先看一下大致劃分 堆 存放內容:     ·大多數建立的物件     ·陣列值 GC情況:

JVM記憶體結構?為什麼需要GC?

原 https://blog.csdn.net/tonytfjing/article/details/44278233 JVM結構、記憶體分配、垃圾回收演算法、垃圾收集器 1.方法區(Method Area) 2.堆區(Heap) 3.虛擬機器棧(VM Stack) 4.本地方法棧(

知識點整理1:JVM記憶體結構

  JVM把記憶體分為如下幾個區域: 1.方法區(Method Area) 2.堆區(Heap) 3.虛擬機器棧(VM Stack) 4.本地方法棧(Native Method Stack) 5.程式計數器(Program Counter R

JVM記憶體結構佈局

Java的記憶體結構 JVM記憶體結構主要有三大塊:堆記憶體、方法區和棧。 堆記憶體是JVM中最大的一塊由年輕代和老年代組成,而年輕代記憶體又被分成三部分,Eden空間、From Survivor空間、To Survivor空間,預設情況下年輕代按照8:1:1的比例

深入淺出JVMjvm記憶體結構,類載入器圖,雙親委託模式,堆記憶體,GC解析,GC演算法)

目錄 Java虛擬機器的記憶體結構:  類載入器圖: 雙親委託模式: 堆記憶體: GC解析圖: GC演算法 Java虛擬機器的記憶體結構:  類載入器圖:   雙親委託模式: Java允許建立和JDK自帶類

一、基礎篇(JVM記憶體結構

一.概念 JAVA的JVM的記憶體可分為3個區:堆(heap)、棧(stack)和方法區(method) 1)堆區: a.儲存的全部是物件,每個物件都包含一個與之對應的class的資訊。(class的目的是得到操作指令) b.jvm只有一個堆區(heap)被所有執行緒共享,堆中不存放

JVM-JVM記憶體結構

一、概念 Java虛擬機器——JVM,,JVM我們可以想象為一個DOS程式,java之所以能做到“一次編譯,處處執行”,就是因為它的存在。java程式從原始碼到執行三個階段:編碼--編譯--執行,其中jvm在其中的角色就是編譯階段,將.class檔案解釋為機器碼,也就是說,只要有了jvm,那麼不管

深入理解JAVA虛擬機器2:JVM記憶體結構

記憶體結構一覽 在上一篇文章中,我們最後給出了一幅圖 這幅圖中,就包含了JVM的記憶體結構的所有組成元素,他們分別是:java堆記憶體、java棧、方法區、本地方法區以及pc暫存器,接下來我們就對這些區域逐一介紹。 java堆       Java堆是Java虛擬

JVM記憶體結構詳解

主要內容如下: JVM啟動流程 JVM基本結構 記憶體模型 編譯和解釋執行的概念   一、JVM啟動流程: JVM啟動時,是由java命令/javaw命令來啟動的。 二、JVM基本結構: JVM基本結構圖: 《深入理解Ja

Jvm--01、Jvm記憶體結構

HotSpot VM,它是Sun JDK和OpenJDK中所帶的虛擬機器,也是目前使用範圍最廣的Java虛擬機器。 話不多說上圖、Jvm記憶體結構圖: 深入理解Java虛擬機器(第二版)如圖:     方法區和堆是執行緒共享的、所有會有執行緒安

JVM記憶體結構 VS Java記憶體模型 VS Java物件模型

Java作為一種面向物件的,跨平臺語言,其物件、記憶體等一直是比較難的知識點。而且很多概念的名稱看起來又那麼相似,很多人會傻傻分不清楚。比如本文我們要討論的JVM記憶體結構、Java記憶體模型和Java物件模型,這就是三個截然不同的概念,但是很多人容易弄混。 可以這樣說

Mybatis的原理與JVM記憶體結構(面試題)

Mybatis的原理 1.Mapper 介面在初始SQL SessionFactory註冊的 2.Mapper 介面註冊在名為MapperRegistry類的 HasMap中 key=Mapper class   value = 建立當前Mapper的工廠  3.

JVM記憶體結構(Java 工程師成神之路·基礎篇·JVM

第一章 JVM記憶體結構 第一章 JVM記憶體結構 為什麼要了解JVM記憶體管理機制 JVM自動的管理記憶體的分配與回收,這會在不知不覺中浪費很多記憶體,導致JVM花費很多時間去進行垃圾回收(GC) 記憶體洩露,導致JVM記憶體最終不夠用 JVM記憶體結構

JVM記憶體結構------堆,棧,方法區,以及堆和棧的區別

一 、 定義 堆:FIFO佇列優先,先進先出。JVM只有一個堆區被所有執行緒所共享!堆存放在耳機快取中,呼叫物件的速度相對慢一些,生命週期由JVM的垃圾回收機制定。 棧:FILO先進後出,暫存資料的地方。每個執行緒都包含一個棧區!棧存放在一級快取中,存取速度較快,“棧是限定

JVM記憶體結構--新生代及新生代裡的兩個Survivor區(下一輪S0與S1交換角色,如此迴圈往復)、常見調優引數

轉自http://www.cnblogs.com/duanxz/p/6076662.html 一、為什麼會有年輕代   我們先來屢屢,為什麼需要把堆分代?不分代不能完成他所做的事情麼?其實不分代完全可以,分代的唯一理由就是優化GC效能。你先想想,如果沒有分代,那我們

Java虛擬機器詳解----JVM記憶體結構

http://www.cnblogs.com/smyhvae/p/4748392.htm   主要內容如下: JVM啟動流程 JVM基本結構 記憶體模型 編譯和解釋執行的概念   一、JVM啟動流程: JVM啟動時,是由java命令/javaw命令來啟