JVM系列1:内存区域

1.JVM运行区域内存划分

2.各内存区域详细介绍

2.1 程序计数器

  程序计数器是一块很小的内存区域,它作为前线程所执行的字节码的行号指示器,指向当前class文件的执行代码的行数。字节码解释器工作时,通过改变程序计数器的数值,来选取下一条将要执行的字节码指令。分支、循环、跳转、异常处理、线程恢复等功能都需要依赖这个计数器来完成。

  当线程切换->恢复时,为了恢复之前的运行环境,因此每个线程必须有自己独立的程序计数器。

  作用:

  • 指示当前字节码执行行数,为分支、循环、跳转、异常处理等提供流程处理的基准。
  • 为线程切换和恢复提供记录线程执行位置的功能。

2.2 Java虚拟机栈(VM Stack)

  java虚拟机栈由一个个栈帧组成,每个栈帧对应着一个被调用的方法,栈帧中包括以下内容:

  •  局部变量表:主要是存放了编译器可知的各种数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)
  • 操作数栈:虚拟机把操作数栈作为它的工作区——大多数指令都要从这里弹出数据,执行运算,然后把结果压回操作数栈。后进先出
  • 动态链接:包含一个指向运行时常量池中该栈帧所属方法的引用。

方法返回地址:一般来说,方法正常退出时,调用者的PC计数器的值就可以作为返回地址,栈帧中很可能保存了这个计数器值,而方法异常退出时,返回地址是要通过异常处理器来确定的,栈帧中一般不会保存这部分信息。方法退出的过程实际上等同于把当前栈帧出栈,因此退出时可能执行的操作有:恢复上层方法的局部变量表和操作数栈,如果有返回值,则把它压入调用者栈帧的操作数栈中,调整PC计数器的值以指向方法调用指令后面的一条指令。

2.3 本地方法栈:

  本地方法栈与Java栈的作用和原理非常相似。区别只不过是Java栈是为执行Java方法服务的,而本地方法栈则是为执行本地方法(Native Method)服务的。

2.4 堆

  堆是Java虚拟机所管理的最大的一片内存区域,它是所有线程共享的,在虚拟机启动时创建。

  唯一功能:存放对象实例,几乎所有的对象实例和数组都在堆中分配内存。

  java堆是垃圾收集器管理的主要区域,因此也被称为GC堆。

  堆中包含以下几个区域:

  

  *JVM为了更好更快地回收内存空间,实行分代垃圾回收算法。

  *JDK1.8中已经移除了永久代,用元空间(MetaSpace)替代,元空间是物理内存区域。

2.5 方法区

  方法区与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息(包括类的名称、方法信息、字段信息)、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 Non-Heap(非堆),目的应该是与 Java 堆区分开来。

  

2.6 运行时常量池

   JDK1.7之前,在方法区中有一个非常重要的部分就是运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。

  <JDK1.7及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池。>

  常量池包含以下内容:

  

原文地址:https://www.cnblogs.com/LearnAndGet/p/9761754.html