1. 程式人生 > >[JVM]Java記憶體區域與記憶體溢位異常

[JVM]Java記憶體區域與記憶體溢位異常

這裡寫圖片描述

Java記憶體區域可以分為執行緒共享和執行緒私有:
執行緒共享: Java堆、方法區
執行緒私有: 虛擬機器桟、本地方法區、程式計數器

1 Java堆

Java堆是虛擬機器鎖管理的記憶體中最大的一塊。堆是執行緒共享區域,在虛擬機器啟動時建立。堆的唯一目的就是存放物件的例項 , 幾乎所有的物件例項都在這裡分配,不過隨著JIT編譯器的發展和逃逸技術的成熟,棧上分配和標量替換技術使得這種情況發生著微妙的變化,對上分配正變得不那麼絕對。

附:在Java程式語言和環境中,即時編譯器(JIT compiler,just-in-time compiler)是一個把Java的位元組碼(包括需要被解釋的指令的程式)轉換成可以直接傳送給處理器的指令的程式。當你寫好一個Java程式後,源語言的語句將由Java編譯器編譯成位元組碼,而不是編譯成與某個特定的處理器硬體平臺對應的指令程式碼(比如,Intel的Pentium微處理器或IBM的System/390處理器)。位元組碼是可以傳送給任何平臺並且能在那個平臺上執行的獨立於平臺的程式碼。

Java堆是垃圾回收器管理的主要區域,所以也叫“GC堆”。由於現在的垃圾收集器基本上都是採用分代收集演算法,所以Java堆還可細分為:新生代和老生代。在細緻一點可分為Eden空間,From Survivor空間,To Survivor空間。如果從記憶體分配的角度看,執行緒共享的Java堆可劃分出多個執行緒私有的分配緩衝區。不過無論如何劃分,都與存放內容無關,無論哪個區域,都是用來存放物件例項。細分的目的是為了更好的回收記憶體或者更快的分配記憶體。

Java堆可以是物理上不連續的空間,只要邏輯上連續即可,主流的虛擬機器都是按照可擴充套件的方式來實現的。如果當前對中沒有記憶體完成物件例項的建立,並且不能在進行記憶體擴充套件,則會丟擲OutOfMemory異常。

2 方法區

方法區又叫“非堆”,用來存放已經載入的類資訊,常量,靜態變數,JIT編譯後的程式碼。

方法區的限制非常寬鬆,處了不需要連續的記憶體區域和可以選擇固定大小和可擴充套件外,還可以選擇不識閒垃圾回收。一般來說方法區的記憶體回收比較難以令人滿意。當方法區無法滿足記憶體分配需求時將丟擲OutOfMemoryError異常。

執行時常量池 : 是方法區的一部分,Class檔案中除了有類的版本、欄位、方法、介面等資訊外,還有一項資訊是常量池用於儲存編譯器生成的各種字面量和符號引用,這部分資訊將在類載入後放到方法區的執行時常量池中。 一般來說,除了儲存Class檔案中描述的符號引用外,還會把翻譯出來的直接引用也儲存在執行時常量池中。

常量池是方法區的一部分,所以受到記憶體的限制,當無法申請到足夠記憶體時會丟擲OutOfMemoryError異常。

3 程式計數器

一塊較小的記憶體區域,用以存放執行緒執行的位元組碼的行號指示器。每條執行緒都有一個獨立的的程式計數器,各執行緒間的計數器互不影響,因此該區域是執行緒私有的。

當執行緒在執行一個Java方法時,該計數器記錄的是正在執行的虛擬機器位元組碼指令的地址,當執行緒在執行的是Native方法(呼叫本地作業系統方法)時,該計數器的值為空。另外,該記憶體區域是唯一一個在Java虛擬機器規範中麼有規定任何OOM(記憶體溢位:OutOfMemoryError)情況的區域。

4 Java虛擬機器桟

虛擬機器桟描述的是Java方法執行的記憶體模型:每個方法在執行的時候都會建立一個桟幀用於存放區域性變量表、運算元桟、動態連結、方法出口等。
在Java虛擬機器規範中,對這個區域規定了兩種異常情況:

1、如果執行緒請求的棧深度大於虛擬機器所允許的深度,將丟擲StackOverflowError異常。
2、如果虛擬機器在動態擴充套件棧時無法申請到足夠的記憶體空間,則丟擲OutOfMemoryError異常。

1. 區域性變量表

區域性變量表是一組變數值儲存空間,用於存放方法引數和方法內部定義的區域性變數,其中存放的資料的型別是編譯期可知的各種基本資料型別、物件引用(reference)和returnAddress型別(它指向了一條位元組碼指令的地址)。區域性變量表所需的記憶體空間在編譯期間完成分配,即在Java程式被編譯成Class檔案時,就確定了所需分配的最大區域性變量表的容量。當進入一個方法時,這個方法需要在棧中分配多大的區域性變數空間是完全確定的,在方法執行期間不會改變區域性變量表的大小。

區域性變量表的容量以變數槽(Slot)為最小單位。在虛擬機器規範中並沒有明確指明一個Slot應占用的記憶體空間大小(允許其隨著處理器、作業系統或虛擬機器的不同而發生變化),一個Slot可以存放一個32位以內的資料型別:boolean、byte、char、short、int、float、reference和returnAddresss。reference是物件的引用型別,returnAddress是為位元組指令服務的,它執行了一條位元組碼指令的地址。對於64位的資料型別(long和double),虛擬機器會以高位在前的方式為其分配兩個連續的Slot空間。

虛擬機器通過索引定位的方式使用區域性變量表,索引值的範圍是從0開始到區域性變量表最大的Slot數量,對於32位資料型別的變數,索引n代表第n個Slot,對於64位的,索引n代表第n和第n+1兩個Slot。

在方法執行時,虛擬機器是使用區域性變量表來完成引數值到引數變數列表的傳遞過程的,如果是例項方法(非static),則區域性變量表中的第0位索引的Slot預設是用於傳遞方法所屬物件例項的引用,在方法中可以通過關鍵字“this”來訪問這個隱含的引數。其餘引數則按照引數表的順序來排列,佔用從1開始的區域性變數Slot,引數表分配完畢後,再根據方法體內部定義的變數順序和作用域分配其餘的Slot。

區域性變量表中的Slot是可重用的,方法體中定義的變數,作用域並不一定會覆蓋整個方法體,如果當前位元組碼PC計數器的值已經超過了某個變數的作用域,那麼這個變數對應的Slot就可以交給其他變數使用。這樣的設計不僅僅是為了節省空間,在某些情況下Slot的複用會直接影響到系統的而垃圾收集行為。

2. 運算元棧

運算元棧又常被稱為操作棧,運算元棧的最大深度也是在編譯的時候就確定了。32位資料型別所佔的棧容量為1,64為資料型別所佔的棧容量為2。當一個方法開始執行時,它的操作棧是空的,在方法的執行過程中,會有各種位元組碼指令(比如:加操作、賦值元算等)向操作棧中寫入和提取內容,也就是入棧和出棧操作。

Java虛擬機器的解釋執行引擎稱為“基於棧的執行引擎”,其中所指的“棧”就是運算元棧。因此我們也稱Java虛擬機器是基於棧的,這點不同於Android虛擬機器,Android虛擬機器是基於暫存器的。

基於棧的指令集最主要的優點是可移植性強,主要的缺點是執行速度相對會慢些;而由於暫存器由硬體直接提供,所以基於暫存器指令集最主要的優點是執行速度快,主要的缺點是可移植性差。

3. 動態連線

每個棧幀都包含一個指向執行時常量池(在方法區中)中該棧幀所屬方法的引用,持有這個引用是為了支援方法呼叫過程中的動態連線。Class檔案的常量池中存在有大量的符號引用,位元組碼中的方法呼叫指令就以常量池中指向方法的符號引用為引數。這些符號引用,一部分會在類載入階段或第一次使用的時候轉化為直接引用(如final、static域等),稱為靜態解析,另一部分將在每一次的執行期間轉化為直接引用,這部分稱為動態連線。

4. 方法返回地址

當一個方法被執行後,有兩種方式退出該方法:執行引擎遇到了任意一個方法返回的位元組碼指令或遇到了異常,並且該異常沒有在方法體內得到處理。無論採用何種退出方式,在方法退出之後,都需要返回到方法被呼叫的位置,程式才能繼續執行。方法返回時可能需要在棧幀中儲存一些資訊,用來幫助恢復它的上層方法的執行狀態。一般來說,方法正常退出時,呼叫者的PC計數器的值就可以作為返回地址,棧幀中很可能儲存了這個計數器值,而方法異常退出時,返回地址是要通過異常處理器來確定的,棧幀中一般不會儲存這部分資訊。

方法退出的過程實際上等同於把當前棧幀出站,因此退出時可能執行的操作有:恢復上層方法的區域性變量表和運算元棧,如果有返回值,則把它壓入呼叫者棧幀的運算元棧中,調整PC計數器的值以指向方法呼叫指令後面的一條指令。

5 本地方法桟

該區域與虛擬機器棧所發揮的作用非常相似,只是虛擬機器棧為虛擬機器執行Java方法服務,而本地方法棧則為使用到的本地作業系統(Native)方法服務。

6 直接記憶體區

直接記憶體區並不是虛擬及規範中定義的記憶體區域。但是這部分記憶體也被頻繁使用,而且也可能導致OutOfMemoryError異常出現。

JDK 1.4中新加入了NIO類,引入一種基於通道與緩衝區的I/O方式,他可以使用Native函式直接分配堆外記憶體,然後通過一個儲存在Java堆中的DirectByteBuffer物件作為這塊記憶體的引用進行操作。這樣內顯著提高效能,因為避免了在Java堆和Native堆中來回複製資料。

相關推薦

學習筆記1:深入理解Java虛擬機器——JVM高階特性最佳實踐_走進java_java記憶體區域記憶體溢位異常

第一部分:走進java Java虛擬機器 程式碼在華章下載 jdk釋出了六個命令列工具和兩個視覺化故障處理工具。 推薦書籍 設計原本 領域特定語言 現在著名的Java虛擬機器 hotspot vm(預設) jrockit vm j9 vm jdk sun jdk op

《深入理解Java虛擬機器—JVM高階特性實踐 周志明 著》之第2章 Java記憶體區域記憶體溢位異常

1、Java虛擬機器所管理的記憶體包括以下幾個執行時資料區域: 2、程式計數器:          1. 可以看作是當前執行緒所執行的位元組碼的行號指示器,是一塊較小的記憶體空間;  &nbs

JAVA虛擬機器(JVM)劃重點 第二章 Java記憶體區域記憶體溢位異常 之 虛擬機器物件

本部落格參考《深入理解Java虛擬機器》(第二版)一書,提取重點知識,再加以個人的理解編寫而成。轉載請標明來源。 JAVA虛擬機器(JVM)劃重點 第二章 Java記憶體區域與記憶體溢位異常 之 虛擬機器物件 Java物件的建立 1、類載入過程

JAVA虛擬機器(JVM)劃重點 第二章 Java記憶體區域記憶體溢位異常 之 執行時資料區域

本部落格參考《深入理解Java虛擬機器》(第二版)一書,提取重點知識,再加以個人的理解編寫而成。轉載請標明來源。 JVM劃重點 第二章 Java記憶體區域與記憶體溢位異常 之 執行時資料區域 概述 執行時資料區域 程式計數器 Java虛擬機

深入理解JVM—第二章:Java記憶體區域記憶體溢位異常

1,概述 Java較C、C++,Java可以利用虛擬機器的自動記憶體管理機制,避免繁瑣的記憶體分配與回收。不容易出現記憶體洩漏和記憶體溢位問題。 記憶體洩漏:指程式申請到的記憶體空間不再歸還(無法歸還),可使用完該記憶體空間的程式也不能再訪問該空間(

Java記憶體區域記憶體溢位異常 JVM筆記1

目錄 執行時資料區域 程式計數器 虛擬機器棧 本地方法棧 堆 方法區 直接記憶體 物件的記憶體佈局 物件頭 例項資料 對齊填充 物件的訪問定位 執行時資料區域 JAVA虛擬機器在執行Java程式的過程中會把它所管理的記憶體劃分為若干個不同的

JVM 第2章 Java記憶體區域記憶體溢位異常

可以參考下,這個寫的簡練 https://blog.csdn.net/seu_calvin/article/details/51404589 1 概述 對於java程式設計師來說,在虛擬機器自動記憶體管理機制的幫助下,不需要為每一個new操作去寫配對的delete/free程式碼,不

[JVM]Java記憶體區域記憶體溢位異常

Java記憶體區域可以分為執行緒共享和執行緒私有: 執行緒共享: Java堆、方法區 執行緒私有: 虛擬機器桟、本地方法區、程式計數器 1 Java堆 Java堆是虛擬機器鎖管理的記憶體中最大的一塊。堆是執行緒共享區域,在虛擬機器啟動時建立。

JVM筆記》之一:Java記憶體區域記憶體溢位異常

Java與C++之間有一堵由記憶體動態分配和垃圾收集技術所圍成的高牆,牆外面的人想進去,牆裡面的人卻想出來。 按照《Java虛擬機器規範(第2版)》的規定,Java虛擬機器所管理的記憶體將包括以下幾個執行時資料區域,來個圖更加直觀點,如下圖所示:   解釋下各個部分 程式計數器: Program Coun

JVM面試題整理-Java記憶體區域記憶體溢位異常、垃圾收集器和記憶體分配策略

1、Java虛擬機器記憶體(執行時資料區域)的劃分,每個區域的功能 關於JVM 執行時記憶體劃分的例項參考: http://www.cnblogs.com/hellocsl/p/3969768.html?utm_source=tuicool&

java虛擬機器—-java記憶體區域記憶體溢位異常

一,java虛擬機器所管理的執行時資料區域分為:程式計數器、java虛擬機器棧、本地方法棧、java堆、方法區、執行時常量池。                     1,程式計數器:

《深入理解java虛擬機器》讀書筆記(二)---- Java記憶體區域記憶體溢位異常

執行時資料區域 java虛擬機器所管理的記憶體將會包括以下幾個執行時資料區域: 1、程式計數器 程式計數器是一塊較小的記憶體空間,它可以看作是當前執行緒所執行位元組碼的行號指示器。在虛擬機器的概念模型裡,位元組碼直譯器的工作就是通過改變這個計數器的值來選取下一條需要執

JVM-Java記憶體區域記憶體溢位

JVM虛擬機器執行時資料區結構分為:      其中方法區和堆是所有執行緒共享的記憶體區域,而Java棧、本地方法棧、程式計數器是執行緒私有的。 我們詳細介紹執行時資料區的各個區域及其作用。  程式計數器:   一塊較小的記憶體空間,位元組碼指示器工作時通過改變計數器的值來選取下一條需

虛擬機器學習之一:java記憶體區域記憶體溢位異常

1.執行時資料區域 java虛擬機器在執行java程式的過程中會把它所管理的記憶體劃分為若干個不同的資料區域。這些區域都有各自的用途和建立、銷燬時間,有的區域伴隨虛擬機器程序的啟動而存在,有些區域則依賴使用者執行緒的啟動和結束而建立和銷燬。 1.1程式計數器 程式計數器

JVM(二) 記憶體區域記憶體溢位異常

一 執行時資料區域: ![這裡寫圖片描述](https://img-blog.csdn.net/20180914092258976?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1lvbGFuZGVyYQ==/fo

java記憶體區域記憶體溢位異常

執行是記憶體區域 java虛擬機器在執行java程式的過程中會把它所管理的記憶體劃分為若干個不同的資料區域。 1.執行緒獨有的記憶體區域 (1)程式計數器(Program Counter Register) 這塊記憶體區域很小,它是當前執行緒所執行的位元組碼的行號

Java 記憶體區域記憶體溢位異常(二)

一、虛擬機器中Java物件的建立 語言層面上,建立Java物件通常僅僅是一個new關鍵字而已。 在虛擬遇到new指令時: 1、首先檢查這個指令的引數是否能在常量池中定位到一個類的符號引用,並檢查這個類的符號引用代表的類是否已經載入,解析和初始化過。如果沒有,則必須執行類

Java 記憶體區域記憶體溢位異常(三)

實戰:OutOfMemoryError 異常 參考:《深入理解Java虛擬機器》-jvm高階特性與最佳實現(周志明著) 之前的兩篇中介紹Java虛擬機器中各個執行時記憶體區域的作用,這節中通過人為異常的方式驗證各個執行時區儲存的內容 一、Java堆溢位 Java堆中用

Java記憶體區域記憶體溢位異常簡單總結

目錄 1.簡述 2.作用 3.注意 1.簡介 3.異常 1.簡述 1. 簡述 2.異常 1.簡述 2.異常 1.JVM執行時資料區域簡圖 Java虛擬機器執行時資料區 2.程式計數器(Program Co

深入理解java虛擬機器---java記憶體區域記憶體溢位異常---3垃圾回收機制GC

  一、垃圾回收---物件存活演算法:     1、引用計數器法:在物件身上放上一個計數器,當有引用則加一,引用失效則減一,為零則可回收。(無法解決物件相互引用)     2、可達性分析法(java),GC roots為起始點,從節點向下搜尋,搜尋路徑為引用鏈,不在引用鏈的物件則是可回收的物件