JVM運行時數據區

JVM運行時數據區

當一個Java程序要啓動時,操作系統會啓動一個Java虛擬機(JVM)的實例來運行這個java程序。每個Java程序的運行總有一個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--
發佈了23 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章