java虚拟机(HotSpot)之运行时数据区

it2024-07-17  37

jvm之类加载器

文章目录

jvm运行时数据区简介jvm系统线程堆方法区虚拟机栈本地方法栈本地接口程序计数器执行引擎直接内存

jvm运行时数据区

简介

运行时数据区包含方法区,虚拟机栈,本地方法栈,堆,程序计数器,执行引擎,本地库接口,本地方法库。 每一个jvm都有一个对应的runtime实例 ,可以把它理解为一个运行时数据区 在hotspot jvm里 ,每个线程都与操作系统的本地线程直接映射。 当一个java线程准备好执行以后,此时一个操作系统的本地线程也同时创建, java线程执行终止后,本地线程也会回收。 操作系统负责所有线程的安排调度到任何一个可用的cpu上,一旦本地线程初始化成功, 他就会调用java线程中的run方法。

jvm系统线程

可以使用jconsole等其他调试工具,可以看到后台的线程运行。 虚拟机线程: 这种线程的操作是需要jvm达到安全点才会出现, 这些操作必须在不同的线程中发生的原因是他们都需要jvm达到安全点,这样堆才不会变化, 这种线程的执行类型包括’’stop-the-world’’的垃圾收集。线程栈收集,线程挂起以及偏向锁撤销 周期任务线程: 这种线程是时间周期事件的体现,比如中断,他们一般用于周期性操作的调度执行 GC线程:这种线程对在jvm里不同种类的垃圾收集行为提供了支持 编译线程:这种线程在运行时会将字节码编译成本地代码 信号调度线程:这种线程接收信号并发送给jvm,在它内部通过调用适当的方法进行处理

堆的描述

方法区

方法区包含 类信息,常量,静态变量。即时编译器编译的代码。 方法区(元空间,代码换成缓存)和堆是线程共享的。 程序计数器和本地方法栈及虚拟机栈是线程各有一份的,就是独有的。 方法区在1.8时改为元空间

方法区的描述

虚拟机栈

虚拟机栈描述

本地方法栈

Java虚拟机用于管理java方法,而本地方法栈用于管理本地方法的调用 本地方法栈,也是线程私有的 允许被实现成固定或者是可动态扩展的内存大小, 内存溢出的方面和虚拟机栈是相同的 在本地方法栈中等地本地方法,在执行引擎执行时加在本地方法库 当某个线程调用一个本地方法时,他就进入了一个全新的并且不再受虚拟机限制的世界, 他和虚拟机拥有同样的权限,本地方法可以通过本地方法接口来访问虚拟机内部运行时数据区 他甚至可以直接使用本地处理器中的寄存器 直接从本地内存的堆内存中分配任意数量的内存 注意:并不是所有的jvm都支持本地方法,因为java虚拟机规范并没有明确要求本地方法栈的使用语言, 具体实现方式,数据结构等,如果不支持本地方法,那么也无需实现本地方法栈 Hotspot jvm的虚拟机栈和本地方法栈和二为一了

本地接口

本地方法接口,本地方法库 不存在于运行时数据区 一个native method 就是一个java调用非java代码的接口 , 一个navite method是这样一个java方法,又非java语言实现 本地接口的作用就是融合不同的编程语言为java所用,但是并非只有java有这么一个特性, 其他语言也有类似于这样的功能。 使用标识符navite标识的就是本地方法,他可以和所有的java标识一起使用, 但不能和Abstract使用,因为使用abstract表示的是抽象方法没有方法体, 而使用navite标识的表示有方法体,但是不是使用java语言实现的 为什么要使用本地方法, 是因为有些层次的任务用java实现不容易,或者效率问题 与java环境外交互 与操作系统交互

程序计数器

程序计数器也叫pc寄存器 作用: pc寄存器用来存储指向下一条指令的地址,也即将要执行的指令代码, 由执行引擎读取下一条指令,其实就是指向当前栈帧的代码的指令,也就是当前方法的指令 如果是执行本地方法,则是未指定值(undefined) 它是一块很小的内存空间,几乎可以忽略不计,允许速度块,它是线程私有的 它是程序控制流的指示器,分支,循环,跳转,异常处理,线程恢复等基础功能都需要依赖这个计数器来完成。 字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。 它是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError情况的区域 这块区域即没有gc,也没有oom 使用pc寄存器存储字节码指令地址有什么作用? jvm字节码解释器就需要通过改变pc寄存器的值来明确下一条应该执行什么样的字节码指令 为什么使用pc寄存器记录当前线程的执行地址?线程不共享的 可以记录当前线程执行到了哪里,因为需要不停的切换线程,这时候切换回来,就得知道从哪里开始继续执行 pc寄存器为什么会被设定为线程私有? 我们都知道所谓的多线程在一个特定的时间段内只会执行其中某一个线程的方法, cpu会不停的做任务切换,这样必然导致经常中断或恢复, 为了能够准确得记录各个线程正在执行得当前字节码指令地址, 最好得办法自然是为每一个线程都分配一个pc寄存器,这样就不会互相干扰 由于cpu时间片轮限制,众多线程并发执行过程中,任何一个确定得时刻, 一个处理器或者多核处理器中的一个内核,只会执行某个线程中的一条指令

执行引擎

Jvm负责装载字节码到内部,但不能直接运行在操作系统上,因为字节码指令并非等价于本地机器指令, 那么如果要让一个java程序运行起来,就需要执行引擎, 他的任务是将字节码指令解释/编译为对应平台的本地机器指令

直接内存

直接内存是在java堆外的,直接向系统申请的内存空间 直接内存的访问会优于java堆,读写性能高, 因此频繁的操作读写可以考虑使用直接内存, 也会出现OutOfMemoryError错误,他的大小不受jvm的大小控制, 但是受系统的内存控制,当超出了系统的内存大小,就会报异常 缺点: 分配回收成本高 不受jvm内存回收管理 直接内存大小可通过MaxDirectMemorySize设置 如果不设置,默认和堆空间的最大值是一样的
最新回复(0)