运行时数据区
内存是非常重要的资源 是硬盘和CPU的中间仓库及桥梁 承载着操作系统和应用程序的实时运行 JVM内存布局规定了Java在运行过程种内存申请、分配、管理的策略 保证了JVM的高效稳定运行 不同的JVM对内存的划分方式和管理机制存在着部分差异
方法区和堆 与进程对应(多个线程共享)
程序计数器 本地方法栈 虚拟机栈 与线程对应(单独线程私有)
若有5个线程 则它们的程序计数器 本地方法栈 虚拟机栈相互独立 但共享方法区和堆
程序计数器 (PC寄存器)
程序计数器(Program Counter Register)中 Register的命名源于CPU的寄存器 寄存器存储指令相关的现场信息 CPU只有把数据装载到寄存器才能运行 JVM中的PC寄存器是对物理PC寄存器的一种抽象模拟 并非广义上所指的物理寄存器
作用:PC寄存器用来存储指向下一条指令的地址 也即将要执行的指令代码 由执行引擎读取下一条指令
介绍:
- 它是一块很小的内存空间 是运行速度最快的存储区域
- 每个线程都有自己的程序计数器 是线程私有的 生命周期和线程的生命周期保持一致
- 任何时间一个线程都只有一个方法在执行 也就是所谓的当前方法 程序计数器会存储当前线程正在执行的Java方法的JVM指令地址 多种如果是在执行native方法 则是未指定值(undefined)
- 是程序控制流的知识其 分支、循环、跳转、异常处理、线程恢复等基础功能都依赖计数器完成
- 字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令
- 它是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryEoor情况的区域
int i = 10;
int j = 20;
int k = i + j;
int i = 10;
int j = 20;
int k = i + j;
String s = "abc";
System.out.println(i);
System.out.println(k);
常见问题:
- 使用PC寄存器存储字节码指令地址有什么用?
- 为什么使用PC寄存器记录当前线程的执行地址?
因为CPU需要不停的切换各个线程 这时候切换回来以后 就得知道接着从哪儿开始继续执行
JVM的字节码解释器就需要通过改变PC寄存器的值来明确下一条应该执行什么样的字节码指令
- PC寄存器为什么会被设定为线程私有?
为了能够准确的记录各个线程正在执行的当前字节码指令地址 最好的办法自然是为每一个线程都分配一个PC寄存器 这样各个线程之间可以进行独立计算 从而不会出现相互干扰的情况
本地方法栈
本地方法接口的理解
简单的讲,一个Native Method就是一个Java调用非Java代码的接口,一个Native Method是这样的一个Java方法:该方法的实现由非Java语言实现,如C。这个特征并非Java锁特有,很多其他的编程语言都有这一机制。
- native关键字修饰本地方法
- native和abstract不能共用
- 本地方法可以用访问修饰符修饰
为什么要使用Native Method?
- 与Java环境外交互:有时Java应用需要与Java外面的环境交互,这是本地方法存在的主要原因。本地方法为我们提供了一个非常简洁的接口,我们无需去了解Java应用之外的繁琐的细节。
- 与操作系统交互:JVM支持着Java语言本身和运行时库,它是Java程序赖以生存的平台,它由一个解释器(解释字节码)和一些连接到本地代码的库组成。然而不管怎样,他毕竟不是一个完整的系统,它经常依赖于一些底层系统的支持,这些底层系统常常是强大的操作系统。**通过使用本地方法,我们得以用Java实现了jre的与底层系统的交互,甚至JVM的一些部分都是用C写的。**还有,如果我们要使用一些Java语言本身没有提供封装的操作系统的特性时,我们也需要使用本地方法。
- Sun’s Java:**Sun的解释器是用C实现的,这使得它能像一些普通的C一样与外部交互。**jre大部分也是用Java实现的,它也通过一些本地方法与外界交互。
本地方法栈的理解
- Java虚拟机栈用于管理Java方法的调用,而本地方法栈用于管理本地方法的调用。
- 本地方法栈也是线程私有的
- 允许被实现成固定或者是可扩展的内存大小(在内存溢出方面是相同的)
- 如果线程请求分配的栈容量超过本地方法栈允许的最大容量,Java虚拟机会抛出一个StackOverflowError异常
- 如果本地方法栈可以动态扩展,并且在尝试扩展的时候无法申请到足够的内存,或者在创建新的线程的时候没有足够的内存去创建对应的本地方法栈,那么Java虚拟机会抛出一个OutOfMemoryError异常
- 本地方法是使用C语言实现的
- 它的具体做法是Native Method Stack中登记native方法,在Execution Engine执行时加载本地方法库。
- 当某个线程调用一个本地方法时,它就进入了一个全新的并且不再受虚拟机限制的世界。它和虚拟机拥有相同的权限。
- 本地方法可以通过本地方法接口来访问虚拟机内部的运行时数据区
- 可以直接使用本地处理器中的寄存器
- 直接从本地内存的堆中分配任意数量的内存
并不是所有的JVM都支持本地方法。因为Java虚拟机规范并没有明确要求本地方法栈的使用语言、具体实现方式、数据结构等。
如果JVM产品不打算支持native方法,也无需实现本地方法栈。
内存的堆中分配任意数量的内存并不是所有的JVM都支持本地方法。因为Java虚拟机规范并没有明确要求本地方法栈的使用语言、具体实现方式、数据结构等。
如果JVM产品不打算支持native方法,也无需实现本地方法栈。- 在Hotspot JVM中,直接将本地方法栈和虚拟机栈合二为一