Java虚拟机内存区域

Java虚拟机内存区域和常见字节码指令

学习小笔记,参考书籍:《深入理解java虚拟机》,《深入理解计算机系统》,《码出高效 java开发手册》

运行时数据区域

  1. 可以看下图,其中绿色背景的表示是所有下线程共享的数据区
    在这里插入图片描述

程序计数器

  1. 这里指的是一块较小的内存区域,可以看作当前线程所执行字节码的行号指示器。虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选择取下一条需要执行的字节码指令。Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,即一个任意时刻一个处理器(对于多核处理器来说是一个内核)都会执行一条线程中的指令。线程切换过程必要要求以后能够恢复到正确的执行位置,所以这个程序计数器是线程独有的。如果线程正在执行java方法,那么这个计数器记录的就是正在执行的虚拟机字节码指令地址。如果执行的是native方法,那么计数值为空。该内存区域是唯一一个在Java虚拟机中没有规范任何OutOfMemoryError的方法。

  2. 程序计数器,按字面意思,十分容易让人到的是处理器中的程序计数器,它们既有相似的地方又有不同的地方

    • 最直观的就是,处理器中的程序计数器是寄存器,而Java虚拟机中的程序计数器是内存区域。既然是寄存器和内存,那么一断电大家都失忆了。
    • 处理器中的程序计数器保存的是下一条指令的内存地址,在指令取出后,程序计数器被更新(地址加一)。实际上,无论在单核还是多核系统中,一个CPU看上去像并发执行多个进程,这是通过处理器的上下文切换(context switch)实现的,操作系统跟踪保存进程运行的所有状态信息,这种状态就是上下文,比如程序计数器PC和寄存器文件的当前值,以及主存的内容。操作系统决定将当前进程转移到某一个新进程中时,就会发生上下文切换,即保存进程的上下文,恢复新进程的上下文。
    • Java虚拟机的程序计数器记录的是字节码指令的地址,当不同线程切换时,像处理器一样因为需要知道新执行上一次执行的字节码指令位置,而能成功恢复现场的道理正是由于程序计数器是线程独有的,线程之间的计数器互不影响。

Java虚拟机栈

  1. 同程序计数器,Java虚拟机栈也是线程私有的,生命周期和线程相同。虚拟机栈描述的是Java方法执行的内存模型:每一个方法在执行的同时都会创建栈帧,用于储存局部变量表、操作栈、动态链接、方法出口等信息
  2. 局部变量表存放了编译期可知的各种基本数据类型和对象引用(reference类型,不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象句柄火其它与此对象相关的位置)和returnAddress类型(指向一条字节码指令的地址)。长度为64位的double和long类型数据回占用两个局部变量空间,其余只占用一个。局部变量表所需内存空间是在编译器 完成分配的,方法运行期不会改变其大小。
  3. 操作栈是一个初始状态为空的桶式结构栈,在方法执行过程中,会有各种指令往栈中写入和提取信息.jvm执行引擎是基于栈的执行引擎,其中栈指操作栈.字节码指令集的定义都是基于栈类型的.栈的深度在方法元信息的stack属性中.
  4. 栈溢出异常(StackOverflowError)的出现就是由于线程请求的栈深入大于虚拟机所允许的深度。如果虚拟机栈可以动态扩展但是扩展中无法得到足够内存,那么就会抛出OutOfMemoryError。

本地方法栈

  1. 类似Java虚拟机栈的作用,只是Java虚拟机栈位虚拟机执行Java方法(字节码)服务,而本地方法栈则为使用到的Native方法服务,也是线程独有的。虚拟机规范中对本地方法栈中方法使用的语言、使用方式和数据结构没有强制规定。

Java堆

  1. 线程共享的一片内存区域,该区域存放对象实例,几乎所有对象实例都会在这里分配。Java堆是垃圾收集器管理的主要区域,故很多时候被称为GC堆(garbage collected heap)。
    • 从内存回收的角度看,由于现在的垃圾收集器基本采用分代收集算法,故Java堆中可以细分为新生代和老生代,再细致一点有Eden空间、From Survivor空间、To Survivor空间
    • 从内存分配角度看,Java堆中还可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)
    • 无论怎么划分,存储的还是对象实例。
  2. Java堆可以处于物理上不连续的内存空间中,只要逻辑连续即可。

方法区

  1. 线程共享区域,储存已被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。别名Non-Heap(非堆),为了和Java堆区分。
  2. 很多习惯在HotSpot虚拟机上开发部署的“老鸟”喜欢把方法区称为永久代(Permanent Generation),本质两者不等价,只是因为HotSpot虚拟机设计团队选择把GC分代收集扩展到方法区,或者使用永久代来实现方法区而已,这样子HotSpot的垃圾收集器可以像管理Java堆一样管理这部分内存,省去专门位方法区编写的内存管理代码。
  3. Java虚拟机规范中对方法区限制宽松,除了可以像Java堆中不需要连续的物理内存和可以选择固定大小或者可扩展外,还可以选择不进行垃圾回收。相对而言,垃圾收集行为在这个区域是比较少出现的,该区域内存的回收目标主要是针对常量池的回收和类型的卸载。
  4. 方法区无法满足内存分配需求时,将抛出OutOfMemoryError。
  5. 运行时常量池(Runtime Constant Pool)是方法区的一部分,Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译器生成的各种字面变量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。相对于Class文件常量池的另外一个重要特征是具备动态性,Java不要求常量一定只有在编译器才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得较多得是String得intern()方法。

直接内存(Direct Memory)

  1. 并不是虚拟机运行时数据区得一部分,也不是Java虚拟机规范中定义得内存区域,但这部分被频繁使用,也可以导致OutOfMemoryError发生。JDK1.4加入NIO类,引入基于通道Channel和缓冲区Buffer得IO方式,可以使用Native函数库直接分配堆外内存,通过储存在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这可以显著提高性能,因为避免了在Java堆中和Native堆中来回复制数据。
  2. 本机的直接内存不受Java堆大小限制,收到本机内存(RAM、SWAP区或者分页文件)大小和处理器寻址空间的限制。

常见字节码指令

  1. 结合上面的内存区域来学习字节码指令总是很愉快的

加载或存储指令

在某个栈帧中,通过指令操作数据在虚拟机栈的局部变量表与操作栈之间来回传输,常见指令如下

  1. 将局部变量加载到操作栈中.如ILOAD(将int类型的局部变量压入栈)和ALOAD(将对象引用的局部变量压入栈)
  2. 从操作栈顶存储到局部变量表:如ISTORE,ASTORE
  3. 将常量加载到操作栈顶
    • ICONST : 加载-1到5的数
    • BIPUSH : 即Byte Immediate PUSH, 加载-128到127的数
    • SIPUSH : 即Short Immediate PUSH, 加载 -32768到32767的数
    • LDC : 即Load Constant,加载-2147483648 ~ 2147483647或者是字符串

运算指令

  1. 对两个操作栈帧上的值进行运算,并把结果写入操作栈顶,如IADD,IMUL

类型转换指令

  1. 显式转换两种不同的数值类型,如I2L,D2F

对象创建于访问指令

根据类进行对象的创建,初始化,方法调用等

  1. 创建对象:NEW,NEWARRAY
  2. 访问属性:GETFIELD,PUTFIELD,GETSTATIC
  3. 检查实例类型指令:INSTANCEOF,CHECKCAST

操作栈管理指令

  1. 出栈操作:POP即一个元素,POP2即两个元素
  2. 复制栈顶元素并压入栈:DUP

方法调用与返回指令

  1. 调用对象的实例方法:INVOKEVIRTUAL
  2. 调用实例初始化方法,私有方法,父类方法:INVOKESPECIAL
  3. 调用类静态方法:INVOKESTATIC
  4. 放回void:RETURN

同步指令

jvm使用方法结构中的ACC_SYNCHRONIZED标志同步方法,指令集中有MONITORENTER和MONITOREXIT支持synchronized语义

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值