1. 程式人生 > >Java虛擬機器記憶體——棧、堆、Non-heap

Java虛擬機器記憶體——棧、堆、Non-heap

Java中通過多執行緒使得多個任務同時執行處理所有的執行緒共享JVM記憶體區域main memory,而每個執行緒又有自己的工作記憶體,當執行緒與記憶體區域進行互動時,資料從主存拷貝到工作記憶體,進而交由執行緒處理。

Java虛擬機器記憶體模型中定義的訪問操作與物理計算機處理的基本一致。


JVM的邏輯記憶體模型如下圖:


1、程式計數器(Program Counter Register)

程式計數器是一塊較小的記憶體空間,其存放的是當前執行緒所執行的位元組碼的行號指示器。在虛擬機器的概念模型裡(僅是概念模型,各種虛擬機器可能會通過一些更高效的方式去實現),位元組碼直譯器工作時就是通過改變這個計數器的值來選取下一條需要執行的位元組碼指令,分支、迴圈、跳轉、異常處理、執行緒恢復等基礎功能都需要依賴這個計數器來完成。

由於Java 虛擬機器的多執行緒是通過執行緒輪流切換並分配處理器執行時間的方式來實現的,在任何一個確定的時刻,一個處理器(對於多核處理器來說是一個核心)只會執行一條執行緒中的指令。因此,為了執行緒切換後能恢復到正確的執行位置,每條執行緒都需要有一個獨立的程式計數器,各條執行緒之間的計數器互不影響,獨立儲存,我們稱這類記憶體區域為“執行緒私有”的記憶體。

如果執行緒正在執行的是一個Java 方法,這個計數器記錄的是正在執行的虛擬機器位元組碼指令的地址;如果正在執行的是Natvie 方法,這個計數器值則為空(Undefined)。此記憶體區域是唯一一個在Java 虛擬機器規範中沒有規定任何OutOfMemoryError 情況的區域。

2、Java虛擬機器棧(Java Virtual Machine Stacks)

與程式計數器一樣,Java虛擬機器棧也是執行緒私有的,其生命週期與執行緒相同。

虛擬機器棧描述的是Java 方法執行的記憶體模型:每個方法被執行的時候都會同時建立一個棧幀(Stack Frame ①)用於儲存區域性變量表操作棧動態連結方法出口等資訊。每一個方法被呼叫直至執行完成的過程,就對應著一個棧幀在虛擬機器棧中從入棧到出棧的過程。

經常有人把Java 記憶體區分為堆記憶體(Heap棧記憶體(Stack,這種分法比較粗糙,Java 記憶體區域的劃分實際上遠比這複雜。這種劃分方式的流行只能說明大多數程式

員最關注的、與物件記憶體分配關係最密切的記憶體區域是這兩塊。其中所指的在後面會專門講述,而所指的就是現在講的虛擬機器棧,或者說是虛擬機器棧中的區域性變量表部分

區域性變量表存放了編譯期可知的各種基本資料型別(boolean、byte、char、short、int、float、long、double)、物件引用(reference 型別,它不等同於物件本身,根據不同的虛擬機器實現,它可能是一個指向物件起始地址的引用指標,也可能指向一個代表物件的控制代碼或者其他與此物件相關的位置)和returnAddress 型別(指向了一條位元組碼指令的地址)。其中64 位長度的long 和double 型別的資料會佔用2 個區域性變數空間(Slot),其餘的資料型別只佔用1 個。區域性變量表所需的記憶體空間在編譯期間完成分配,當進入一個方法時,這個方法需要在幀中分配多大的區域性變數空間是完全確定的,在方法執行期間不會改變區域性變量表的大小。

丟擲異常:如果執行緒請求的棧深度大於虛擬機器所允許的深度,將丟擲StackOverflowError異常;如果虛擬機器棧可以動態擴充套件(當前大部分的Java 虛擬機器都可動態擴充套件,只不過Java 虛擬機器規範中也允許固定長度的虛擬機器棧),當擴充套件時無法申請到足夠的記憶體時會丟擲OutOfMemoryError 異常

3、本地方法棧(Native Method Stacks)

本地方法棧與虛擬機器棧的作用非常相似,虛擬機器棧為虛擬機器執行Java方法(也就是位元組碼)服務,而本地方法棧則是為虛擬機器使用的Native方法服務的。

虛擬機器規範中對本地方法棧中的方法使用的語言、使用方式與資料結構並沒有強制規定,因此具體的虛擬機器可以自由實現它。甚至有的虛擬機器(譬如Sun HotSpot 虛擬機器)直接就把本地方法棧和虛擬機器棧合二為一。與虛擬機器棧一樣,本地方法棧區域也會丟擲StackOverflowError 和OutOfMemoryError異常

4、Java堆(Java Heap)

對於大多數應用來說,Java 堆是Java 虛擬機器所管理的記憶體中最大的一塊。Java 堆是被所有執行緒共享的一塊記憶體區域,在虛擬機器啟動時建立。

Java堆中唯一的目的就是存放物件例項,幾乎所有的物件例項都在這裡分配記憶體。

這一點在Java 虛擬機器規範中的描述是:所有的物件例項以及陣列都要在堆上分配①,但是隨著JIT 編譯器的發展與逃逸分析技術的逐漸成熟,棧上分配、標量替換②優化技術將會導致一些微妙的變化發生,所有的物件都分配在堆上也漸漸變得不是那麼“絕對”了。

Java堆是垃圾收集器管理的主要區域,因此很多時候也被稱作“GC堆”(Garbage Collected Heap)。

根據Java 虛擬機器規範的規定,Java 堆可以處於物理上不連續的記憶體空間中,只要邏輯上是連續的即可,就像我們的磁碟空間一樣。在實現時,既可以實現成固定大小的,也可以是可擴充套件的,不過當前主流的虛擬機器都是按照可擴充套件來實現的(通過-Xmx和-Xms 控制)。如果在堆中沒有記憶體完成例項分配,並且堆也無法再擴充套件時,將會丟擲OutOfMemoryError 異常

4、方法區(Method Area)——又名Non-Heap

方法區與Java堆一樣,是各個執行緒共享的記憶體區域,用於儲存已被虛擬機器載入的類資訊常量靜態變數即時編譯器編譯後的程式碼等資料。雖然Java 虛擬機器規範把方法區描述為堆的一個邏輯部分,但是它卻有一個別名叫做Non-Heap(非堆),目的應該是與Java 堆區分開來。

根據Java 虛擬機器規範的規定, 當方法區無法滿足記憶體分配需求時, 將丟擲OutOfMemoryError 異常


5、執行時常量池(Runtime Constant Pool)

執行時常量池是方法區的一部分。Class檔案中除了有類的版本、欄位、方法、介面等描述資訊外,還有一項資訊是常量池,用於存放編譯期生成的各種字面量和符號引用,這部分內容在類載入後存放到方法區的執行時常量池中。

6、直接記憶體(Direct Memory)

直接記憶體並不是虛擬機器執行時資料區的一部分,也不是Java虛擬機器規範中定義的記憶體區域,但是這部分記憶體也被頻繁地使用,而且也可能導致OutOfMemoryError 異常出現。應用在某些場景中能顯著提高效能,因為其避免了在Java堆和Native堆中來回複製資料。

顯然,本機直接記憶體的分配不會受到Java 堆大小的限制,但是,既然是記憶體,則肯定還是會受到本機總記憶體(包括RAM 及SWAP 區或者分頁檔案)的大小及處理器定址空間的限制。伺服器管理員配置虛擬機器引數時,一般會根據實際記憶體設定-Xmx等引數資訊,但經常會忽略掉直接記憶體,使得各個記憶體區域的總和大於實體記憶體限制(包括物理上的和作業系統級的限制),從而導致動態擴充套件時出現OutOfMemoryError異常



邏輯記憶體模型我們已經看到了,那當我們建立一個物件的時候是怎麼進行訪問的呢?

Java 語言中,物件訪問是如何進行的?物件訪問在Java 語言中無處不在,是最普通的程式行為,但即使是最簡單的訪問,也會涉及Java 棧、Java 堆、方法區這三個最重要記憶體區域之間的關聯關係,如下面的這句程式碼:

Object obj = new Object();

假設這句程式碼出現在方法體中,那“Object obj”這部分的語義將會反映到Java 的本地變量表中,作為一個reference 型別資料出現。而“new Object()”這部分的語義將會反映到Java 中,形成一塊儲存了Object 型別所有例項資料值(Instance Data,對象中各個例項欄位的資料)的結構化記憶體,根據具體型別以及虛擬機器實現的物件記憶體布局(Object Memory Layout)的不同,這塊記憶體的長度是不固定的。另外,Java 堆中還必須包含能查詢到此物件型別資料(如物件型別、父類、實現的介面、方法等)的地址資訊,這些型別資料則儲存在方法區中

由於reference 型別在Java 虛擬機器規範裡面只規定了一個指向物件的引用,並沒有定義這個引用應該通過哪種方式去定位,以及訪問到Java 堆中的物件的具體位置,因此不同虛擬機器實現的物件訪問方式會有所不同,主流的訪問方式有兩種:使用控制代碼直接指標


相關推薦

Java虛擬機器記憶體——Non-heap

Java中通過多執行緒使得多個任務同時執行處理,所有的執行緒共享JVM記憶體區域main memory,而每個執行緒又有自己的工作記憶體,當執行緒與記憶體區域進行互動時,資料從主存拷貝到工作記憶體,進而交由執行緒處理。 Java虛擬機器記憶體模型中定義的訪問操作與物理計算

對這個java虛擬機器記憶體的,年輕代,年老代,永久代i,搞不太清楚。年輕代年老代存放在還是。新版虛擬機器沒有永久代是個啥情況

1.什麼是jvm?(1)jvm是一種用於計算裝置的規範,它是一個虛構出來的機器,是通過在實際的計算機上模擬模擬各種功能實現的。(2)jvm包含一套位元組碼指令集,一組暫存器,一個棧,一個垃圾回收堆和一個儲存方法域。(3)JVM遮蔽了與具體作業系統平臺相關的資訊,使Java

深入理解java虛擬機器-記憶體管理異常處理

深入理解Java虛擬機器:JVM高階特性與最佳實踐 閱讀筆記(記憶體原理、異常處理): 1.     Jvm執行時,記憶體劃分如圖所示:   2.     程式計數器:        Jvm將這個計數看作當前執行緒執行某條位元組碼的行數,會根據計數器的值來選取需

Java虛擬機器(四)——物件的建立儲存和定位

物件的建立   Java是一門面向物件的程式語言,Java 程式執行過程中無時無刻都有物件被創建出來,在語言層面上,建立物件(例如克隆,反序列化)通常僅僅是一個new關鍵字而已,例如下面的語句。 Object obj = new Object(); 其實

《深入理解Java虛擬機器》個人讀書總結——JAVA虛擬機器記憶體

《深入理解Java虛擬機器》個人讀書總結——JAVA虛擬機器記憶體 最近在讀《深入理解Java虛擬機器》,網上對Java虛擬機器的總結有很多,自己覺得自己也應該記錄一點個人的讀書總結,以便日後複習方便。 隨著開發工作的逐漸深入,對Java的理解不能止步於crud,Java不像C語言

java虛擬機器(第二版) 第二章總結 (三)-手工復現java虛擬機器記憶體溢位(OutOfMemoryError異常)

  文章概述 的java虛擬機器記憶體溢位的簡要概述,復現堆記憶體,棧記憶體,方法區的執行時常量池記憶體等區域的溢位情況,以及上述區域發生記憶體溢位的判斷方式和解決思路。   1,概述:      IDE為eclipse,需要在執

jvm學習筆記(1)——java虛擬機器記憶體區域

一、java記憶體區域:      1、程式計數器(執行緒私有):     記憶體中較小的記憶體空間,可以當做當前執行緒所執行位元組碼的行號指示器。如分支、迴圈、跳轉、異常處理、執行緒恢復都需要依賴這個計數器完成。 2、java虛擬機

Java虛擬機器 記憶體管理與垃圾回收

java和C++之間有一堵由記憶體自動分配與垃圾回收所圍成的高牆,外面的人想進來,裡面的人想出去 主要內容 記憶體分佈 垃圾回收機制 垃圾收集器 Java記憶體分佈 當java虛擬機器執行程式時,會把由虛擬機器管理的記憶體劃分為不同的區域,他們的作用不同,建立和銷燬時間也不同,有的是虛擬

Java虛擬機器記憶體模型與執行緒

Java虛擬機器—記憶體模型與執行緒 Lyon Keep balance,Be a better man! ​關注他 3 人讚了該文章 前言: 本文主要介紹Java的記憶體模型和Java執行緒。 Java記憶體模型的主要目標是定義程式中各個變數的訪問規則,即在JVM

JVM系列第6講:Java 虛擬機器記憶體結構

看到這裡,我相信大家對於一個 Java 原始檔是如何變成位元組碼檔案,以及位元組碼檔案的含義已經非常清楚了。那麼接下來就是讓 Java 虛擬機器執行位元組碼檔案,從而得出我們最終想要的結果了。在這個過程中,Java 虛擬機器會載入位元組碼檔案,將其存入 Java 虛擬機器的記憶體空間中,之後進行一系列的初始化

JVM調優--------理解java虛擬機器記憶體模型

java虛擬機器記憶體模型是java程式執行的基礎,為了能使Java應用程式正常執行,JVM虛擬機器將記憶體資料分為程式計數器,虛擬機器棧,本地方法棧,Java堆和方法區 程式計數器用於存放下一條執行的指令;虛擬機器棧和本地方法棧用於存放函式呼叫堆疊資訊;java堆用於存放Java程式執行時所需

Confluence 提高Java虛擬機器記憶體

Confluence 提高Java虛擬機器記憶體 版本 系統:CentOS release 6.8 (Final)Java版本:1.8.0_162Confluence版本:6.8.5 問題描述 confluence記憶體使用率的配置都是預設的,相對會比較低,可以根據實際server的配置情況,升級記憶

JVM篇:淺談java虛擬機器記憶體模型

  博主最近嘗試著瞭解JVM,博主目前的一些理解,總之會隨著博主的深入瞭解慢慢完善吧 圖片來自網路 當JVM執行時,便會建立這五個區域,退出時銷燬。 JVM的五個區域:方法區、堆、棧(也可以稱為虛擬機器棧)、程式計數器、本地方法棧 博主在這裡說明一下:方法區概括了元空間

Java虛擬機器幀和方法呼叫

棧幀和方法呼叫 執行時棧幀結構 區域性變量表 運算元棧 動態連線 返回地址 方法呼叫 解析 分派 靜態分派 動態分配 虛擬機器動態分配的實現

Java虛擬機器-記憶體管理

參考深入理解Java虛擬機器 執行時記憶體包括: 方法區(Method Area) 虛擬機器棧(VM Stack) 本地方法棧(Native Method Stack) 堆(Heap) 程式計數器(Program counter Register) 程式計數器

JAVA虛擬機器記憶體劃分學習

JAVA虛擬機器所管理的記憶體將分為以下幾個區:  1.程式計數器:主要包括程式的分支、迴圈、跳轉、異常處理等基礎功能;  2.棧:主要用於儲存區域性變數、方法出口、物件引用等資訊; 是執行緒私有的,生命週期與執行緒相同;  3.堆:主要儲存物件的例項;是執

java 虛擬機器記憶體劃分,類載入過程以及物件的初始化

涉及關鍵詞: 虛擬機器執行時記憶體 java記憶體劃分 類載入順序  類載入時機  類載入步驟  物件初始化順序  構造程式碼塊順序 構造方法 順序 記憶體區域   java記憶體圖  堆 方法區 虛擬機器棧 本地方法棧 程式計數器  區域性變量表   棧幀  java堆 執行時常量池   直接記憶體

Java 虛擬機器記憶體溢位問題和解決方法

一什麼是記憶體溢位 1記憶體溢位是指應用系統中存在無法回收的記憶體或使用的記憶體過多,最終使得程式執行要用到的記憶體大於虛擬機器能提供的最大記憶體。 2 Java的記憶體管理就是物件的分配和釋放問題。 在Java中,記憶體的分配是由程式完成的,而記憶體的釋

Java虛擬機器記憶體結構介紹

文章目錄 一 前言 二 JVM記憶體結構 三 程式計數器 四 虛擬機器棧 五 本地方法棧 六 GC堆 七 方法區 八 執行時常量池 九 直接記憶體 十 總結 一

Java JVM】Java虛擬機器記憶體分配幾個原則

1、大多數情況下,物件在新生代Eden區中分配。當Eden區沒有足夠空間進行分配時,虛擬機器將發起一次Minor GC 2、大物件直接進入老年代。大物件指需要大量連續記憶體空間的Java物件,最典型的