1. 程式人生 > >Java記憶體區域與記憶體溢位異常簡單總結

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

目錄

1.簡述

2.作用

3.注意

1.簡介

3.異常

1.簡述

1. 簡述

2.異常

1.簡述

2.異常

1.JVM執行時資料區域簡圖

Java虛擬機器執行時資料區

2.程式計數器(Program Counter Register)

 1.簡述

程式計數器是執行緒私有的,也就是說每個執行緒都有自己的程式計數器。它可以看做是當前執行緒正在執行的位元組碼的行號指示器,也就是jvm執行class檔案的時候正在執行多少行,這個程式計數器的值就是多少。

2.作用

第一,實現指令跳轉。位元組碼直譯器通過改變程式計數器的值來實現分支,迴圈,跳轉,異常處理等基礎功能,程式計數器的值指示位元組碼直譯器要執行的下一條位元組碼指令的地址。

第二,便於執行緒切換後的恢復。由於一個處理器(或者說是多核處理器的一個核心)每個時間片都只會執行一條執行緒中的指令,jvm要實現多執行緒,就必須不斷的切換執行緒,為了實現執行緒的切換之後還能夠恢復到原來的位置,每個執行緒都必須有一個獨立的程式計數器,指示當前執行緒執行到的位置,便於切換後恢復。

3.注意

如果正在執行的是Native方法(本地方法,也就是用其他語言實現的方法),則這個計數器的值是為空的。並且這個記憶體區域是唯一一個Java虛擬機器規範中沒有規定任何OutOfMemoryError的區域。

3.Java虛擬機器棧(Java Virtual Machine Stacks)

1.簡介

虛擬機器棧描述的是Java方法的記憶體模型,每個方法執行的時候都會建立一個棧幀,儲存區域性變量表,運算元棧,動態連結,方法出口等資訊。這些區域中大多數人最關注的、與物件記憶體分配關係最密切的就是虛擬機器棧中的區域性變量表部分。

2.區域性變量表簡述

區域性變量表中存放的是編譯期可知的各種基本資料型別、物件引用和returnAddress型別(指向了一條位元組碼指令的地址)。

區域性變量表所需要的記憶體空間是在編譯期完成分配的,執行時,這個方法在棧幀中分配的變數空間是完全確定的,不會被改變。

3.異常

在Java虛擬機器規範中,對這個區域規定了兩種異常:

如果執行緒請求的棧的深度大於虛擬機器所允許的深度,則會丟擲StackOverflowError異常;

如果虛擬機器可以動態擴充套件,但擴充套件時無法申請到足夠的記憶體,則丟擲OutofMemoryError異常。

4.本地方法棧(Native Method Stack)

本地方法棧與虛擬機器棧作用類似,不過描述的是Native方法的記憶體模型,而非Java方法。與虛擬機器棧一樣,也會丟擲StackOverflowError與OutofMemoryError異常。

5.Java堆(Java Heap)

1.簡述

Java堆是執行緒共享的,在虛擬機器啟動時建立,它的唯一目的就是存放物件的例項,幾乎所有的物件例項都在這裡分配記憶體。

Java堆是垃圾收集器管理的主要區域,很多時候也稱為“GC堆”。

從記憶體回收角度看,由於垃圾收集器目前採用的基本都是分代收集演算法,Java堆便可以根據這個演算法劃分,詳細的演算法請讀者自行查閱。

從記憶體分配角度看,Java堆是執行緒共享的,為了更好地回收記憶體或者說更快地回收記憶體,Java堆可能會劃分出多個執行緒私有的分配緩衝區。

2.異常與注意

Java堆的記憶體空間在物理上可以是不連續的,在邏輯上是連續的即可。在實現時,既可以為固定大小,也可以是可擴充套件的,如果Java堆中已經沒有記憶體再可以分配,並且堆無法擴充套件時,則會丟擲OutOfMemoryError異常。

6.方法區(Method Area)

1. 簡述

方法區是執行緒共享的,儲存的是已經被虛擬機器載入的類的資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料。

執行時常量池(Runtime Constant Pool)是方法區的一部分,存放的是編譯期生成的各種字面量和符號引用,類載入之後便被存放。

執行時常量池具備動態性,執行期間也可能將新的常量放入池中,一個例子就是String類的intern()方法。

2.異常

當方法區無法滿足記憶體分配需求時,丟擲OutOfMemoryError異常。

7.直接記憶體(Direct Memory)

1.簡述

直接記憶體並不是虛擬機器執行時資料區的一部分,但是經常被使用,而且也會出現OutOfMemoryError異常。

典型例項是NIO類通過Native函式庫直接分配java堆以外的記憶體,然後儲存在Java堆中的DirectByteBuffer物件作為這個記憶體的引用進行操作。由於避免了在Java堆和Native堆中來回複製資料,所以能夠在某些場景下提高效能。

2.異常

這部分的異常主要是由於在配置虛擬機器引數時忽略了直接記憶體區域,導致各個記憶體區域的總和大於了實體記憶體的限制,從而導致Java堆動態擴充套件時出現OutOfMemoryError異常。

PS:本文所有要點均為筆者閱讀《深入理解Java虛擬機器》一書後的簡單提煉和總結,若有紕漏,望指正。