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--
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值