JVM的内存模型与无用信息回收机制

这篇文章算是对自己学习JVM的一个总结,内容来源比较多就不一一列举了,如果侵犯了您的权益,请与我联系。


对于一个Java程序员来说,学习JVM的重要性在此就不列举了,当你觉得你的java学习和使用中遇到了瓶颈,那你可能需要好好关注这一块,也许从中你会知道你的瓶颈所在。

Java虚拟机是Java语言可以实现“write once, run everywhere"的关键。

1. 首先我们来看java平台的体系结构图:

从上图可以看到,java虚拟机是程序与底层操作系统和硬件无关的关键,实现了程序与操作系统的分离,从而实现了平台无关性。当我们提到说JVM的时候其实是有很多种意思在里面,有可能是虚拟机的规范说明,也有可能是具体某一个厂商的具体实现,我们下面的内容主要是基于HotSpot实现。

2. JVM的体系结构图


JVM的整个体系结构包括几个个部分:类装载子系统负责装载合适名称的类或者接口;执行引擎负责执行装载的类或者接口中的指令;运行时数据区包括方法区,堆,虚拟机栈,程序计数器和本地方法栈五个部分。下面先介绍运行时数据区。

3. 运行时数据区

3.1 程序计数器

       程序计数器所占的内存空间比较小,在内存分析的时候经常被忽略,它的作用是当前线程所在执行的字节码的指示器,这个概念其实和操作系统中的程序计数器的作用是一致的。字节码解释器进行工作的时候就是 通过改变这个程序计数器的值来选择下一条需要执行的字节码指令。注意程序计数器所指向的值是下一条指令的地址。

我们注意到,它是当前线程的指示器,也就是说它是线程私有的,每一个线程都有一个独立的程序计数器。

另外,当线程执行的是本地方法时,程序计数器的值是未定义的(Undefined).

3.2 Java虚拟机栈

       Java虚拟机栈是Java方法执行时的模型,每一个方法在执行的时候都会创建一个栈帧(Stack Frame),.它包括三个区域:局部变量区,运行时环境,操作数栈区。

      1) 局部变量区

            每一个Java方法都有一个一个局部变量的集合。存放了编译期可知的各种基本数据类型,对象引用类型。局部变量表所需要的内存空间在编译期就完成了分配,在执行的过程中不会改变局部变量表的大小。

      2) 运行环境区

           运行环境包括几个方面:动态链接,方法出口,异常处理等。动态链接把在方法调用时的符号引用转化为实际的方法调用,装载一些必要的类以及解释还没有被定义的符号等等。方法出口用于当方法调用正常结束后,执行环境恢复调用者的寄存器,跳过方法的字节码序列,指向需要被接下来执行的字节码地址。异常处理是指捕捉方法执行过程中发生的Error或者Exception。

      3)操作数栈区

           操作数栈是方法执行过程中存储的数据,从操作数栈取出数据计算之后再压入栈中。

3.3 本地方法栈

      其实我觉得本地方法栈和java虚拟机栈是一样的,只是说Java虚拟机栈是由java虚拟机这个虚拟的机器执行的,而本地方法栈是实际的机器执行的。当然这么说有点不严密。简单的说就是本地方法调用时需要的执行环境,也就是C语言方法的栈。

3.4 Java堆

       这个估计是和程序员关系最紧密的一个部分了,再有一个很重要的部分就是下面的方法区。这两个部分基本囊括了java中经常出现的错误,也是下面要讲的和无用信息回收(也就是垃圾回收。这个译法是我导师不推荐的,导师翻译为无用信息回收,所以下面的话我也一直使用无用信息回收)关系最密切的两个部分,所以放在最后来说。好了,回到我们的java堆。Java堆是被所有线程共享的一块内存区域,在虚拟机启动的时候就已经创建了,-Xms -Xmx等参数可以设置堆的大小。堆中存放的是对象实例和数组。注意,在此我没有说所有的对象实例都分配在堆上是有原因的,因为随着编译技术的发展,特别是栈上分配、标量替换等优化技术的发展使得一些对象不再分配在堆上,不过这不影响我们对问题的分析。

        虽然这部分很重要,但是在这边并没有什么要说的,更多的内容在无用信息回收部分,那部分涉及堆上内存的分配策略和回收方法。

3.5 方法区

     方法区也是所有线程共享的一块内存区域,里面存储的是JVM加载的类信息、静态变量、常量和编译后的代码等。其实在我的理解中认为,方法区中存储的是类的信息,也就是编译后的代码,可参考javap命令的结果。对于Hotspot来说,无用信息回收时的永久代就是存储在这个区域的。在方法区中还有一个很重要的概念就是运行时常量池。Class常量池我想大家都知道,它中存放编译期生成的各种字面量和符号引用,具体可用javap命令,结果中的Constant Pool就是指的这一块。而运行时常量池并不需要和Class常量池一样需要编译期生成,运行期也可以有常量被放入运行时常量池。


以上是第一部分,主要的内容是运行时的数据区域,其实和操作系统书中的内容很多都是一致的,这也并不奇怪,因为其实很多的东西都是继承和发展的结果,以前听过一句话说,如果你觉得你学到的东西都是新的,那说明你还没有把握其中的本质,我想古语中的万变不离其宗就是这个道理吧。

 以上内容是对自己的一个总结,错误在所难免,阅者指正!


下一部分总结无用信息回收


       


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值