JVM规范之运行时数据区域

打印 上一主题 下一主题

主题 1733|帖子 1733|积分 5199

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
媒介

为什么要阅读jvm规范?


  • 建立对JVM的基础认知,JVM 规范是对 Java 虚拟机的抽象描述,定义了 Java 虚拟机的架构、功能和举动。它提供了一个同一的尺度,让初学者能够从整体上明白 Java 步伐在虚拟机中的运行原理,包括类加载、内存管理、字节码执行等焦点概念。
  • 避免实现细节干扰,不同的 JVM 实现(如 HotSpot、OpenJ9 等)在具体的实现方式上可能存在差异,包括优化策略、内存布局、垃圾回收算法等。对于初学者来说,直接陷入这些实现细节中,轻易造成肴杂,增加学习的难度。先学习 JVM 规范,可以让初学者在明白了根本原理的基础上,再去学习具体实现时,更轻易明白这些实现的特点和差异,而不是一开始就被复杂的实现细节所困扰。
  • 明白JVM的跨平台设计,Java 语言的一个紧张特性是 “一次编写,到处运行”,这依赖于不同平台上符合 JVM 规范的虚拟机实现。学习 JVM 规范能让初学者明确,只要遵照规范,Java 步伐就能在各种不同的操作系统和硬件平台上运行。这种跨平台的思维方式是 Java 编程的紧张理念,有助于初学者更好地明白 Java 的优势和应用场景,而不仅仅范围于某一种具体的 JVM 实现。
  • 快速学习新技术,JVM 技术在不断发展,新的特性和优化不断被引入。阅读 JVM 规范能让初学者跟上技术发展的步伐,明白新特性的设计目的和原理。当新的 JVM 实现版本发布或出现新的 JVM 相干技术时,基于对规范的明白,初学者能够更轻易地学习和把握这些新知识,而不是依赖于特定实现的履历,由于特定实现可能会随着时间的推移而发生较大变化,而规范相对稳固且具有前瞻性。
阅读本篇文章可以学习到啥?

本篇文章根据jvm8规范的 §2.5编写,阅读本篇文章可以简朴相识JVM的运行时数据区包含哪些部分,相识各个部分的角色和功能,方便后续更加深入地学习JVM关于运行时数据区的细节。
正文

概述

JVM中定义了多种运行时数据区域,但是按照生命周期可以分为两种,一种是跟随JVM启动创建和烧毁的,另一种则是跟随线程创建和烧毁的,每个内存区域都有自己的职责,相互之间也并不是完全的隔离的状态,存在包含关系,jvm对于内存的管理的实现并没有做严格的限制,这也为JVM的实现提供充足的灵活性和扩展性。
JVM线程私有的运行时数据区

pc(program counter) Register

JVM支持多线程同时运行,每个JVM线程都有自己的pc Register,用于记录当前正在执行的字节码指令地点,在任意时刻,一个JVM线程都正在运行一个方法中的字节码指令,对于pc寄存器中存储的内容,包含两种情况:


  • 线程正在执行的方法是一个native method,则PC中的值是 undefined;
  • 线程正在执行的方法是一个非native method,则PC寄存器中存储的是将要执行的字节码指令地点;
因此,JVM要求pc Register的宽度必须在特定的平台上充足容纳returnAddress和本地指针宽度
增补


  • native method是JVM为了实现与别的编程语言进行交互而设计的,教唆用非Java语言实现的方法,步伐员或者用户能够在java步伐中调用这些方法,实现和非Java步伐进行交互;
  • returnAddress是JVM中的一种数据类型,存储的是某个字节码指令的地点,是jsr, ret, jsr_w指令使用的数据类型,可以用于实现步伐逻辑跳转;
JVM Stack

JVM Stack,即Java虚拟机栈,每个JVM线程都独立拥有JVM Stack,它随JVM线程创建而创建,随线程烧毁而烧毁,栈中存储的是帧,和传统编程语言C很类似,栈用来保存局部变量、中心结果,也用于保存方法调用和返回的上下文信息
JVM并不会直接操作栈,只能通过方法的调用和返回间接进行压栈和出栈的操作;有一点区别是,传统语言中栈通常是一段连续的内存空间,但是JVM并没有同样的要求,栈帧也可以在堆上进行分配,因此,可以更加充实的使用碎片化的内存空间;
JVM Stack的空间巨细有两种设计:


  • 如果接纳固定巨细的设计,则每个JVM线程被创建时,栈在初始化时也可以是独立配置的,JVM实现时可以提供给步伐员配置栈巨细的方法;
  • 栈也可以根据实际的计算需求进行动态扩缩容,如果接纳这种动态空间的设计,则JVM实现可以提供给步伐员配置动态上下界的方法;(比如HotSpot JVM步伐,可以在Java步伐启动参数上找到蛛丝马迹)
关于Java虚拟机栈的两种异常情况:


  • 如果一个JVM线程在计算时需要更大的栈中心(所需的空间超出了被允许的巨细),则JVM会抛出StackOverflowError
  • 如果没有额外的空间来满意栈动态扩展或者一个新的JVM线程的创建和初始化,则JVM会抛出OutOfMemoryError
Native Method Stack

本地方法栈,本地方法是使用非Java语言编写的,用于实现Java和其他编程语言进行交互,但这并不是一个必须的模块,根据用户的实际情况而定;


  • 如果JVM在实现时提供了本地方法栈,则本地方法栈随着线程的创建而创建;
  • 如果JVM在实现时不允许加载本地方法,则JVM无需提供本地方法栈的实现;
本地方法栈空间巨细的设计:


  • 本地方法栈的巨细可以是固定的,也可以是动态扩缩容的,JVM的实现可以提供给用户或者步伐员配置本地方法栈巨细和上下界的方法;
关于本地方法栈的异常情况:


  • 针对空间固定巨细的实现,如果一个线程在运行时需要本地方法栈的巨细超出允许的巨细,则JVM会抛出StackOverflowError
  • 如果本地方法栈是可以进行动态扩容的,但是所需的额外空间无法满意或者初始化一个本地方法栈时没有充足的空间,则JVM会抛出OutOfMemoryError
JVM线程共享的运行时数据区

Heap

Heap,即堆,是所有JVM线程共享的一块内存空间,当JVM启动时创建,所有的对象实例和数组都会从堆上分配空间,对象占用的内存从来都不会显式地被开释,而是通过自动存储管理系统进行回收,也就是大名鼎鼎的GC(garbage collector);关于自动存储管理系统,JVM并没有假设任何类型的内存管理系统,而是让实现者根据自己的需求选择相应的内存管理技术;
JVM Heap的空间巨细有两种设计:


  • 堆内存不一定是连续的;
  • 如果堆的巨细是固定的,JVM在实现时可以为步伐员或者用户提供配置堆空间巨细的方法;
  • 堆的巨细可以根据实际情况进行动态扩缩容,JVM在实现时可以为步伐员或者用户提供配置堆空间巨细上下界的方法;(比方HotSpot JVM,但是一般线上使用时,上下界配置巨细是一样的,目的也是避免JVM在运行时频繁的扩缩容带来的性能损耗)
关于堆异常的情况:


  • 如果一次计算需要的内存空间超出自动内存管理系统所能申请的空间巨细,则JVM会抛出OutOfMemoryError
Method Area

Method Area,即方法区,所有的JVM线程共享的一块内存区域,方法区的概念和操作系统进程中的代码段(text segment)有些相似,方法区存储了每个类的布局,比如运行时常量池、字段信息等,还有方法和构造器的指令代码;
方法区在JVM启动时创建,从逻辑上讲,方法区是堆的一部分,但是一种简朴的实现是既不使用GC进行垃圾回收也不会对它进行压缩,JVM规范并没有指定要求方法区的位置和字节码指令的管理策略;
方法区的内存空间巨细设计:


  • 方法区的内存不一定是连续的;
  • 方法区的巨细可以是固定的,也可以是动态的扩缩容的,JVM在实现时可以提供步伐员和用户配置方法区巨细或者上下界的方法;
关于方法区的异常情况:


  • 如果方法区的内存巨细不能够满意一次内存分配的申请,则JVM会抛出OutOfMemoryError
Run-time constant pool

运行时常量池,是从方法区分配的一部分内存空间,是每个类或者接口对应的calss文件中的常量池表,常量池中保存了各种常量,包括数值字面量和字段引用,和传统编程语言中的符号表有点类似,
当一个类或者接口被创建时,运行时常量池也会被创建。
运行时常量池异常的情况:


  • 当创建一个类或者一个接口时,如果运行时常量池所需的空间超出方法区可用空间,则JVM会抛出OutOfMemoryError
总结

本篇文章根据JVM8规范,总结了6种JVM运行时数据区,按照线程私有和全局共享,分成两类:
线程私有的运行时数据区:


  • pc Register
  • java虚拟机栈
  • 本地方法栈(如果JVM允许加载本地方法的话)
线程共享的运行时数据区:



  • 方法区
  • 运行时常量池
参考链接

jvm8s

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

缠丝猫

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表