JVM运行时数据区
当一个Java程序要启动时,操作系统会启动一个Java虚拟机(JVM)的实例来运行这个java程序。每个Java程序的运行总有一个JVM在支撑着它。
一个JVM的运行时数据区结构大致如下:
首先,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程序运行过程中运行时数据区的情况。
这里先略去PC寄存器,也不考虑多线程,因此,Java栈中仅存储着main方法所在的主线程的调用栈。运行Demo demo = new Demo("hello world!")语句后,运行时数据区的当前状态如下图所示:
从上图中应该可以很直观的看到这个运行时数据区的布局了。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--
一个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--