JVM區域劃分
Java虛擬機器所管理的記憶體將會包括以下幾個執行時資料區域:
- 程式計數器(執行緒隔離)
- 虛擬機器棧(執行緒隔離)
- 本地方法棧(執行緒隔離)
- JAVA堆(執行緒共享)
- 方法區(執行緒共享)
(1)程式計數器
程式計數器是一塊較小的記憶體空間,它可以看作是當前執行緒所執行的位元組碼的行號指示器。
- 如果執行緒正在執行的是java方法,這個計數器記錄的是正在執行的虛擬機器位元組碼指令的地址;
- 如果正在執行的是Native方法,這個計數器值為空;
- 此記憶體區域是唯一一個在JAVA虛擬機器規範中沒有規定任何OutOfMemoryError情況的區域
(2)虛擬機器棧
虛擬機器棧的生命週期與執行緒相同。虛擬機器棧描述的是Java方法執行的記憶體模型;每個方法在執行的同時都會建立一個棧幀
用於儲存局:
- 區域性變數表(存放編譯器可知的各種基本資料型別,物件引用型別)
- 運算元棧
- 動態連結
- 方法出口 等
對於虛擬機器棧這個區域規定了兩種異常情況:
- StackOverflowError:執行緒請求的棧深度大於虛擬機器所允許的深度
- OutOfMemoryError:虛擬機器棧在擴充時無法申請到足夠的記憶體空間
(3)本地方法棧(與虛擬機器棧所發揮的作用相似)
- 虛擬機器棧:執行JAVA方法(位元組碼)服務
- 本地方法棧:執行為虛擬機器使用到的Native方法服務
- 本地方法棧也會丟擲
StackOverflowError
和OutOfMemoryError
異常
(4)JAVA堆
JAVA堆是JAVA虛擬機器中記憶體最大的一塊。JAVA堆在虛擬機器啟動時建立,被所有執行緒共享。
- 存放幾乎
所有的物件例項
- 垃圾收集主要管理的就是JAVA堆
- 物理上不連續,邏輯上連續
(5)方法區
方法區域java堆一樣,是各個執行緒共享的記憶體區域,它用於儲存:
- 載入的類資訊
- 常量
- 靜態變數
- 即時編譯器編譯後的程式碼資料
執行時常量池位於方法區,存放執行時產生的常量,比如String物件
。方法區有兩個值注意的地方:
- 物理上不需要連續的記憶體,邏輯上連續即可
- 可選擇固定大小的記憶體區域
- 可選擇不實現垃圾收集
實戰:outofmemoryerror異常
(1)在單執行緒下,無論是由於棧幀太大還是由於虛擬機器棧容量太小,當記憶體無法分配時,虛擬機器丟擲的都是java.lang.StackOverflowError異常。
package cn.test.two;
public class JavaVMStackSOF {
private int stackLength = 1;
public void stackLeak(){
stackLength++;
stackLeak();
}
/**
* 執行結果表明;在單執行緒下,無論是由於棧幀太大還是由於虛擬機器棧容量太小,當
* 記憶體無法分配時,虛擬機器丟擲的都是java.lang.StackOverflowError異常
* @param args
* @throws Throwable
*/
public static void main(String[] args) throws Throwable {
JavaVMStackSOF oom = new JavaVMStackSOF();
try{
oo`這裡寫程式碼片`m.stackLeak();
}catch (Throwable e) {
System.out.println(oom.stackLength);
throw e;
}
}
}
(2)不斷建立多執行緒導致發生OutOfMemory異常。
package cn.test.two;
/**
* 別執行,會當機
* 多執行緒導致記憶體溢位
* @author cjc
*
*/
public class JavaVMStackOOM {
private void dontStop(){
while(true){
}
}
public void stackLeakByThread(){
while(true){
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
dontStop();
}
});
thread.start();
}
}
public static void main(String[] args) {
JavaVMStackOOM oom = new JavaVMStackOOM();
oom.stackLeakByThread();
}
}
(3)方法區的執行時常量池記憶體溢位
package cn.test.two;
import java.util.ArrayList;
import java.util.List;
/**
* 方法區的執行時常量池記憶體溢位
* @author cjc
*
*/
public class RuntimeConstraintPoolOOM {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
int i = 0;
while(true){
list.add(String.valueOf(i++).intern());
}
}
}
在記憶體溢位還是棧溢位方面,關注點在於java棧和java堆的常量池。
JVM是如何判定物件是否應該被回收
引用計數法
原理:給物件中新增一個引用計數器,每當有一個地方引用它時,計數器值就加1,;當引用失效時,計數器值就減1;任何時刻計數器為0的物件就是不可能再被使用的。
缺點:這種演算法不能解決物件之間相互迴圈引用的問題。所以主流的JAVA虛擬機器沒有選用引用計數演算法來管理記憶體。(比如:obja.obj = objb; objb.obj = obja;)可達性分析
原理:通過一系列的稱為“GC Roots”的物件作為起始點,從這些節點開始向下搜尋,搜尋所走過的路徑稱為引用鏈,當一個物件到GC Roots沒有任何引用鏈相連(即不可達)時,則證明此物件不可用。如圖:
在Java中,可作為GC Roots的物件包括:
(1)虛擬機器棧(棧幀中的本地變數表)
(2)方法區中類靜態屬性引用的物件
(3)方法區中常量引用的物件
(4)本地方法棧中JNI
再談引用
相關文章
- JVM記憶體區域劃分JVM記憶體
- JVM的記憶體區域劃分JVM記憶體
- 【深入學習JVM 01】執行時資料區域劃分JVM
- Java的記憶體區域劃分Java記憶體
- JVM系列(二) - JVM記憶體區域JVM記憶體
- JVM 記憶體區域JVM記憶體
- 【JVM記憶體區域】JVM記憶體
- Java虛擬機器記憶體區域劃分Java虛擬機記憶體
- JVM的記憶體區域JVM記憶體
- JVM記憶體元件劃分梳理JVM記憶體元件
- JVM記憶體結構劃分JVM記憶體
- JVM(二)-記憶體區域之執行緒私有區域JVM記憶體執行緒
- JVM執行時資料區域JVM
- Java虛擬機器執行時資料區域劃分Java虛擬機
- JVM及其記憶體結構劃分JVM記憶體
- JVM——記憶體區域:執行時資料區域詳解JVM記憶體
- DDD劃分領域、子域,核心域,支撐域的目的
- JVM-記憶體區域與OOMJVM記憶體OOM
- JVM-概述和記憶體區域JVM記憶體
- JVM之記憶體區域總結JVM記憶體
- Java的記憶體管理機制之記憶體區域劃分Java記憶體
- JVM學習-執行時資料區域JVM
- 從零開始JVM(一):初探JVM執行時資料區域JVM
- JVM系列之一 JVM的基礎概念與記憶體區域JVM記憶體
- Java基礎專題 Jvm記憶體劃分JavaJVM記憶體
- 763. 劃分字母區間
- 區域分佈圖怎麼做,怎麼做區域網格分佈圖
- JVM資料區域與垃圾收集<深入理解JVM讀書筆記>JVM筆記
- 淺談 JVM GC 的安全點與安全區域JVMGC
- JVM執行時記憶體資料區域JVM記憶體
- JVM-棧幀之區域性變數表JVM變數
- JVM 系列文章之 Java 的記憶體區域JVMJava記憶體
- SAP智慧領域概念區分
- 怎麼製作區域分佈圖?區域網格分佈圖怎麼做?
- 位元組面試:領域、子域、核心域、通用域和支撐域怎麼劃分?面試
- 資料倉儲主題域如何劃分
- 小白也能看懂的JVM記憶體區域JVM記憶體
- jvm記憶體區域之虛擬機器棧JVM記憶體虛擬機
- 解決DDD最大難題-如何劃分領域