0%

Java虚拟机:运行时数据区域的理解

一直以来,对Java虚拟机中的运行时数据区域这个概念不是很能理解,今天,就好好来聊一下什么是运行时数据区域。

1.Java编译过程

java整个编译以及运行过程可以简化为:

或者也可以参考下图:

Java源码首先被编译成字节码文件,而这个字节码文件就是实现Java代码跨平台运行的关键,无论是什么平台,只要安装了能够识别字节码文件的JVM(Java Virtual Machine,Java虚拟机),通过JVM对字节码文件进行解析,把字节码转换成具体平台上的机器指令,就可以运行。

2. 运行时数据区域

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而一直存在,有些区域则是依赖用户线程的启动和结束而建立和销毁。

Java虚拟机所管理的内存将会包括以下几个运行时数据区域:

  1. 程序计数器:主要是为多线程服务。由于Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。
  2. Java虚拟机栈:线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
  3. 本地方法栈:本地方法栈(Native M ethod Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别只是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的本地(Native) 方法服务
  4. Java堆(又称”GC堆”, Garbage Collected Heap):对于Java应用程序来说,Java堆(Java Heap)是虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,Java 世界里“几乎”所有的对象实例都在这里分配内存。Java堆是垃圾收集器管理的内存区域.
  5. 方法区:各个线程共享的内存区域,它用于存储已被虚拟机加载 的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。运行时常量池 是方法区的一部分。Class文件中除了有类的版本、字 段、方法、接口等描述信息外,还有一项信息是常量池表(Constant Pool Table),用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是说,并非预置入Class文件中常量池的内容才能进入方法区运行时常 量池,运行期间也可以将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法。

总结:

  1. Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,可以分为两大类:线程私有与线程共享。
  2. 栈是运行时的单位,而堆是存储的单位。即:栈解决程序的运行的问题,即程序如何执行,或者说如何处理数据,堆解决的是数据的存储的问题,即,数据怎么放,放在哪儿,(对象是存储在堆中的,方法中的局部变量是保存到栈(栈帧)当中的。局部变量是基本数据类型,对于引用数据类型,保存的还是引用地址)。
  3. Java堆,又称GC堆,此内存区域的唯一目的就是存放对象实例,Java 世界里“几乎”所有的对象实例都在这里分配内存。
  4. 运行时常量池 是方法区的一部分。