深入理解Java虚拟机随笔之运行时数据区

来源:互联网 发布:淘宝旺旺卖家版2016 编辑:程序博客网 时间:2024/06/05 14:11

        Java虚拟机运行时数据区分为程序计数器、虚拟机栈、本地方法栈、堆和方法区(前三个线程私有,后两个线程共享 )。 

          1.程序计数器

               程序计数器是一块较小的内存空间。可看做当前程序所执行的字节码的行号指示器。在虚拟机的概念模型(注意只是概念模型,因为虚拟机可能通过一些更高效的方式去实现)中,字节码解释器通过程序计数器来选取下一条需要执行的字节码指令。此外,分支循环跳转异常处理线程恢复等基础功能都需要依赖程序计数器来完成。 多线程是通过轮流切换线程并分配处理器来实现的。因此,任何时刻一个处理器只会执行一个线程中的指令。那么,线程切换后如何恢复到正确的执行位置呢?这就需要每个线程都有自己的程序计数器,各线程的计数器互不影响,独立存储。这也说明了程序计数器是线程私有的内存。

            注意:线程执行的是Java方法时,程序计数器记录的是正在执行的字节码指令地址。而如果执行的是native方法,则计数器为空。程序计数器是唯一一个没有在虚拟机规范中规定outofmemroyerror情况的区域。

          2.虚拟机栈

           虚拟机栈是描述Java方法执行的内存模型。每个方法在执行的同时会创建一个栈帧,用来存储局部变量表(存放了编译期中可知的基本类型(8种)、对象引用和returnaddress类型(即指向了一条字节码指令的地址))、操作数栈、动态链接、方法出口等信息。所以一个方法从调用到执行完成的过程就是一个栈帧在虚拟机中入栈到出栈的过程。再说说局部变量表,8字节的long和double占据了两个局部变量空间,其余数据类型只占一个。局部变量表所占空间在编译期间完成分配。方法运行期间不会改变局部变量表的大小。Java虚拟机规范在虚拟机栈这块规定了两种异常状况。①线程请求的栈深度大于虚拟机所允许的深度会抛StackOverflowError②如果虚拟机栈可以动态扩展而无法申请到足够的内存就会抛OutOfMemoryError异常

         3.本地方法栈

           与虚拟机栈类似。区别是虚拟机栈为运行Java方法(字节码)服务,而本地方法栈为虚拟机使用到的native方法服务。具体的虚拟机可以自由的实现自己的本地方法栈。虚拟机规范并没有对其做强制规定。当然,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

         4.堆

         堆是虚拟机所管理内存中最大的一块,可以处于物理上不连续、逻辑上连续的内存空间中(即是现实时既可以是固定大小的也可以是可扩展的。当前主流虚拟机都是按可扩展实现的),在虚拟机启动时创建,其唯一目的是存放对象实例(几乎所有对象实例)。虚拟机规范规定所有的对象实例和数组都在堆上分配,但是随着JIT编译器的发展与逃逸分析技术的日渐成熟,栈上分配与标量替换优化技术将会导致微妙的变化发生,所有对象都在堆上分配也渐渐变得不是那么绝对了。如果堆中没有完成实例内存分配且堆无法再扩展时会抛OutOfMemoryError异常

       5.方法区

          用于存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。同堆一样内存既可以是固定大小的也可以是可扩展的,还可以选择不实现垃圾收集。该区域的内存回收目标主要是针对常量池的回收和对类型的卸载。当方法区无法满足内存分配需求时将抛OutOfMemoryError异常。

          运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。运行时常量池相对于class常量池具有动态性。即并非只有预置入class文件常量池的内容才能进入运行时常量池,运行时也可以将新的常量放入池中。

 ( 初学虚拟机,如有错误,还望大佬不吝赐教 。 )

          



阅读全文
0 0
原创粉丝点击