JVM 运行时数据区

本贴最后更新于 1628 天前,其中的信息可能已经事过景迁

Java 虚拟机在运行 Java 程序的过程中,会将管理的内存分为若干区域,每个区域拥有各自的用途。Java 运行时数据区可以由下图表示:

Java 运行时数据区

运行时数据区有一些会随着虚拟机的创建而创建,随着虚拟机的退出而销毁。另外一些则与线程对应,随着线程的开始和结束而创建和销毁。上图中左侧的 Java 堆和方法区与虚拟机对应,而右侧的程序计数器、虚拟机栈和本地方法区与线程对应。

Java 堆

java 堆在虚拟机启动时即被创建,是供各个线程共享的运行时内存区域,也是所有实例对象和数组对象分配内存的区域。它在虚拟机启动时创建,存储了自动内存管理系统(也就是 Garbage Collector 垃圾收集器)所管理的对象,所使用的内存不要求连续,容量也可以动态扩展。如果实际所需内存超过 GC 所能提供的最大容量,那么虚拟机将会抛出 OutOfMemoryError 异常。

方法区

方法区也是可供各个线程共享的运行时内存区域,它存储了每一个类的结构信息,如运行时常量池、字段数据、方法数据、构造方法和普通方法的字节码内容。它在虚拟器启动时创建,实际内存可以不连续。虚拟机可以选择不进行垃圾收集,如果方法区的内存空间不能满足内存分配请求,那么虚拟机将抛出一个 OutOfMemoryError 异常。

运行时常量池

运行时常量池是 class 文件中每一个类或接口的常量池表的运行时表示形式,具备动态性,既包含编译期可知的常量,也包含运行期解析的常量。每一个运行时常量池都在 Java 虚拟机的方法区中分配,在加载类或接口到虚拟机时,就创建对应的运行时常量池。如果创建时需要的内存超过方法区所能提供的最大值,那么虚拟机将抛出一个 OutOfMemoryError 异常。

程序计数器

Java 虚拟机支持多线程,每个线程都拥有自己的程序计数器。程序计数器可以理解为保存正在执行的字节码指令的地址,通过修改该值来选取下一条需要执行的指令。在任意时刻,一条 Java 虚拟机线程只会执行一个方法,该方法称为当前方法(Current Method),如果这个方法不是本地方法(Native Method),那么程序计数器就保存正在执行的指令地址,否则为 undefined。

Java 虚拟机栈

虚拟机栈和程序计数器一样,是线程私有的,生命周期与线程相同。它与线程同时创建,用于存储栈帧(Stack Frame),该结构包含局部变量表、操作数栈、动态链接、方法出口等信息。局部变量表存放编译期可知的各种基本类型、对象引用和 returnAdress 类型。如果线程请求分配的栈容量超过虚拟机栈容许的最大容量,虚拟机将抛出一个 StackOverFolwError 异常;如果虚拟机栈可以动态扩展,在扩展时无法申请到足够的内存,将抛出 OutOfMemoryError 异常。

本地方法栈

本地方法栈与虚拟机栈相似,虚拟机栈为虚拟机执行 Java 方法提供服务,而本地方法栈为虚拟机使用本地方法服务。同样,本地方法栈也会抛出 StackOverFolwError 和 OutOfMemoryError 异常。

本文参考《深入理解 Java 虚拟机(第二版)》和《Java 虚拟机规范(Java SE 8 版)》,只是对 Java 运行时数据区进行了简单的介绍,其中的细节还未进行展开,如栈帧的结构、Java 堆的细分等。在对 Java 内存有了总体认识后,对后面的学习可以有一定的结构支撑。

补充

虚拟机配置的参数:

  • -Xms Java 堆的最小值,也是初始化值
  • -Xmx Java 堆的最大值,当-Xms 和-Xmx 参数相同时,Java 堆不可扩展
  • -Xss 每个虚拟机栈的容量
  • -Xoss 每个本地方法栈的容量,HotSpot 虚拟机不区分虚拟机栈和本地方法栈,故该参数无效
  • -XX:PermSize 持久代初始容量
  • -XX:MaxPermSize 持久代最大容量

jdk6 和 jdk7 下 String#intern 方法的区别:

jdk6 中调用 String#intern 方法,虚拟机首先会在字符串常量池中查找该字符串,找到后返回常量池中的地址,没有查找到会将字符串复制到常量池,然后返回地址。
jdk7 中调用 String#intern 方法,虚拟机首先会在字符串常量池中查找该字符串,找到后返回常量池中的地址,没有查找到会将字符串的**地址**保存到常量池,然后返回保存的地址。

  • JVM

    JVM(Java Virtual Machine)Java 虚拟机是一个微型操作系统,有自己的硬件构架体系,还有相应的指令系统。能够识别 Java 独特的 .class 文件(字节码),能够将这些文件中的信息读取出来,使得 Java 程序只需要生成 Java 虚拟机上的字节码后就能在不同操作系统平台上进行运行。

    180 引用 • 120 回帖
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖
2 操作
AlanSune 在 2020-06-07 20:39:24 更新了该帖
AlanSune 在 2020-06-07 20:34:42 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...