JVM運行時數據區
一個JVM的運行時數據區結構大致如下:
+---------------+ class文件 ----> |類裝載器子系統 | +---------------+ | | +-------------------------------------------+ | ______ ______ ______ ________ | | | | | | | | | | | | |方法區| | 堆 | |Java棧| |PC寄存器| | | |______| |______| |______| |________| | | 運行時數據區 | +-------------------------------------------+ | | +------------------+ | 執行引擎 | +------------------+圖1 JVM運行時數據區( Download ASCII Picture)
首先,JVM會將編譯後的.class文件通過類裝載子系統進行裝載、連接和初始化。它會分析這個裝載的類,並把類中不同的代碼塊按規則在內存中分配好。圖中的運行時數據區就是由JVM管理的Java程序所使用的內存區域,也是我今天想要理清的內容。它的各部分功能介紹如下:
1、方法區
方法區中存儲的是一個類的類型信息,包括public、private、protected等限定信息,以及當前類及其父類的全限定(路徑)名等。此外,方法區中還存儲着一個類的靜態變量、實例變量、常量池、方法信息等。
2、堆
堆中存儲的是Java程序中用關鍵字new出來的對象和數組。這部分內存的回收是由JVM的GC( Garbage Collection)來完成,堆中的對象可被當前程序的所有線程所共享。存在堆中的對象都有一個指向方法區中該對象所屬類型的指針,這樣才方便與運行時去執行該對象的方法。依據JVM的具體實現,方法區與堆可以在同一片內存區域,JVM會管理彼此之間的邊界。
3、Java棧
Java棧中存儲的是方法的局部變量和對堆中對象的引用,每個Java線程都會在這個Java棧中有一個屬於自己的方法調用棧,棧中的內容以棧幀爲單位進行存儲,每個棧頂棧幀代表着一個線程當前正在執行的方法。
4、PC寄存器
PC寄存器其實不是寄存器,JVM中沒有寄存器,它只是功能類似於PC寄存器,用於指示下一條執行代碼的位置所在。每個線程都在這個PC寄存器中有一個屬於自己的PC寄存器。
以一個實例說明Java程序運行過程中運行時數據區的情況。
/** * 銜山的博客 - http://fengchangjian.com * Copyright (c) 2011 All Rights Reserved. */ package cn.edu.zju.jvm; /** * @author 銜山 * @version $Id: JvmDataSegTest.java, v 0.1 2011-9-27 下午08:48:26 */ class Demo { public static int static_var = 1; public String non_static_var; public Demo(String var) { this.non_static_var = var; } public void echo() { System.out.println(non_static_var); } } public class JvmDataSegTest { public static void main(String[] args) { Demo demo = new Demo("hello world!"); demo.echo(); } }
這裏先略去PC寄存器,也不考慮多線程,因此,Java棧中僅存儲着main方法所在的主線程的調用棧。運行Demo demo = new Demo("hello world!")語句後,運行時數據區的當前狀態如下圖所示:
+-----------------------------------------------------------------------------+ | ______________________________ ________________ ____________________ | | |方法區 | |堆 | |Java棧 | | | | | | | | | | | | +--JvmDataSegTest類型信息--+ | | +------------+ | | +----------------+ | | | | | main()方法 | | | | Demo實例 | | | | 指向Demo的引用 | | | | | | "hello world!" | | | +------------+ | | +----------------+ | | | | | …… | | | | | | | | | +--------------------------+ | | | | | | | | | | | | | | | | +-------Demo類型信息-------+ | | | | | | | | | static_var=1 | | | | | | | | | | non_static_var | | | | | | | | | | echo()方法 | | | | | | | | | | …… | | | | | | | | | +--------------------------+ | | | | | | | |______________________________| |________________| |____________________| | | | | 運行時數據區 | +-----------------------------------------------------------------------------+圖2 測試程序的運行時數據區佈局( Download ASCII Picture)
從上圖中應該可以很直觀的看到這個運行時數據區的佈局了。Demo類的類型信息和JvmDataSegTest類的類型信息都存在方法區中,其中還包括Demo類的靜態變量(static_var)和實例變量(non_static_var)。main()方法中用於構造Demo類的字符串"hello world!"也是存儲在方法區的常量池中。main()方法中new出來的Demo對象存儲在堆中。此時的Java棧中,棧頂應該是主線程的main()方法棧幀,裏面存着一個引用demo,它指向堆中的Demo對象。當main()方法執行到demo.echo()語句時,JVM先從棧中的demo引用出發,找到位於堆中的Demo實例,然後從這個Demo實例中找到echo()方法的引用,繼而定位到方法區中Demo類型信息部分,從中獲取echo()方法的字節碼,執行echo()方法的指令。
Reference:
[1] Bill Venners 著, 曹曉鋼 蔣靖 譯. 深入Java虛擬機[M]. 機械工業出版社. 2003-09.
--EOF--