JVM规范之内存结构
JVM规范中一块很重要的地方就是内存的管理,JVM规范里面在功能上对JVM的内存进行了一定的划分,理解这一块内容对理解JVM的规范有一定的帮助。当然,就像许多规范一样,JVM规范虽然对内存进行了划分,但是各个JVM的实现却不一定会做这样的划分,说地确切一点是负责对应功能的内存肯定在每一个JVM的实现里面都是有的(如果没有提供参数给程序员调整的话,有些对你来说就是不可见的),但是其实现方式可以是五花八门的。另外,JVM对内存的分配和管理事实上是和Java Class文件的格式,JVM的运行机制都有密切相关,如果对这些东西有所了解,那么对内存的管理理解也会有所帮助。
先来看一张图来直观地感受下JVM规范里面是怎样对JVM的内存进行功能上的区分的:
在这张图里面,首先根据内存是线程私有的还是线程共享的,把内存区域分成了两块:
线程私有
这一块区域主要由程序计数器(PC),虚拟机栈(Virtual Machine Stack)和本地方法栈(Native Method Stack)组成
- 程序计数器:同计算机的程序计数器;如果正在执行Java方法,则指向虚拟机字节码指令的地址,如果是native的,这个计算器的值为空。
- 虚拟机栈:虚拟机栈是和线程的生命周期相同的,每创建一个线程,就会创建一个虚拟机栈。而在一个线程中,每调用一个方法,就会在虚拟机栈中创建一个栈帧(Stack Frame),用于保存方法相关的信息,栈帧的具体结构看上图的箭头左边部分:
- 本地变量表(Local Variable):用于保存本地变量,这里的本地变量是指方法的入参以及在方法中声明的变量,如果在编译Java文件的时候加上”-g”参数,然后用”javap -p -verbose”打印出class文件后可以看到一个方法的本地变量表的内容,下面是一个简单的“Hello, world!”程序的main方法的本地变量表:
LocalVariableTable: Start Length Slot Name Signature 0 9 0 args [Ljava/lang/String;
- 操作数栈(Operand Stack):首先要了解JVM的架构是基于栈的指令集,指令的操作都是对栈的操作,所以方法运行的时候的一些参数和中间变量都必须先放入栈中才能够被操作,这里面的栈指的就是操作数栈,注意不要和前面提到的虚拟机栈混为一谈。
- 对运行时常量池的引用(Runtime Constant Pool Reference):这里面主要保存对在方法中调用的方法的符号引用,这些符号引用会在运行时被解析成对方法的真正引用。
- 本地变量表(Local Variable):用于保存本地变量,这里的本地变量是指方法的入参以及在方法中声明的变量,如果在编译Java文件的时候加上”-g”参数,然后用”javap -p -verbose”打印出class文件后可以看到一个方法的本地变量表的内容,下面是一个简单的“Hello, world!”程序的main方法的本地变量表:
- 本地方法栈:本地方法栈的功能和虚拟机栈的作用相同,不同的是本地方法栈服务的对象是本地方法。
线程共享
线程共享这一块区域说起来就一块东西:堆;稍微细分一下可以分为方法区(Method Area)和”存放类实例的区域”
- 方法区:主要存放已被虚拟机加载的类信息、常量、静态变量、即时编译器编译以后的代码,其中运行时常量池也在方法区中。
- “存放类实例的区域”:这一部分内存是存放对象,所有实例化的对象都会放在这个地方。
直接内存
前面看到的都是JVM的运行时数据区的部分,JVM的内存中还有另外一部分叫直接内存(Direct Memory,对应上面的图中的最下方的地方),它不是JVM运行时数据区的一部分,不受JVM的GC管理。其中Java NIO中的Buffer直接在堆外分配的就属于这个部分。

[...] 原文地址:http://www.goldendoc.org/2011/11/jvm_memory_management/ 此条目发表在 演示稿 分类目录。将固定链接加入收藏夹。 ← JVM原理Roadmap [...]
有一处小笔误,用命令
javap -p -verbose查看变量表,而不是javac -p -verbose已经修正,谢谢指出~~
你好,khotyn。在《The Java Virtual Machine Specification(JVMS)-JavaSE7》中搜索整个文档,也没找到“直接内存(Direct Memory)”,请问你是在哪里看到的?
还有,我感觉你这篇文章标题定义的不是很合理,文章里只讲JVM的内存由哪些单元组成,根本没谈及JVM如何分配和释放内存(即管理)。所以,我感觉文章标题改为《JVM规范之内存结构》更合理,这样更好地表达文章会介绍哪些内容。
谢谢!
Hi,Edward,谢谢你关注我们的博客,关于文章标题的问题,的确用“内存结构”更为合理,管理的部分因为会涉及到具体的虚拟机实现,下次会写专门的文章来讲。关于直接内存(Direct Memory)的问题,事实上JVM规范只对JVM的运行时数据区做了一些说明,而没有提到直接内存,但是各个JVM实现的时候,会用到直接内存,比如Sun的NIO的Buffer的实现。所以直接内存这一部分并不属于JVM规范的部分,只是很多的虚拟机实现都由这一部分。
哦,khotyn,非常感谢你的回复。偶明白了,我会阅读你们关于 Java NIO 的相关文章,你们确实很负责啊,文章写得非常详细,这需要很多时间的,我也深有体会。同时也会去 Google 上搜索相关文章,尽量多找几篇高质量的文章一起阅读,以便理解其原理。请问在这方面,你有什么好的建议没?
Hi,,Edward,谢谢你对我们的网站的关心。对于一个学习的主题的话,我会尽量去找一手的资料,比如要了解JVM,会去看看《JVM规范》,另外,再去看看有没有这个主题相关的比较权威的书,个人感觉系统地学习还是看书或者规范之类的更加好,网上优秀的文章可以作为补充。当然,如果身边有相关方面的牛人,多和它做交流,那么学起来也会轻松很多。
[...] 原文地址:http://www.goldendoc.org/2011/11/jvm_memory_management/ [...]