深入理解java虚拟机(一)

概述

一个java程序编译和执行的流程如下:

  1. java编译器将java源代码文件(.java)编译为字节码文件(.class);
  2. 然后由JVM中的类加载器加载各个类的字节码文件;
  3. 加载完成后,由执行引擎执行。
    在程序执行过程中,需要运行时数据区(Runtime Data Area)提供数据,运行时数据区域也就是我们常说的JVM内存。

运行时数据区域

 运行时数据区域主要包括程序计数器虚拟机栈本地方法栈方法区

程序计数器

  1. 程序计数器是当前线程执行的字节码的行号指示器;
  2. 如果当前线程执行的是一个java方法,程序计数器中记录的是正在执行的虚拟机字节码指令的地址;如果执行的是一个Native方法,那么程序计数器值为空;
  3. 程序计数器是线程私有的;
  4. 程序计数器是唯一一个没有规定任何OutOfMemoryError情况的区域。

虚拟机栈

  1. 虚拟机栈是线程私有的;
  2. 虚拟机栈是 java方法执行的内存模型:每一个方法在执行时都会创建一个栈帧,用于存放局部变量表、操作数栈、动态链接、方法出口等信息。
  3. 局部变量表
  • 存放方法中的局部变量和方法参数,包括基本数据类型、对象引用和returnAddress类型;
  • 分配完方法参数后,会依次分配方法内部定义的局部变量;
  • 除了64位的long和double类型数据占用2个局部变量空间(slot),其他占用1个slot;
  • slot可以重用;
  • 不会为局部变量赋初值
  • 大小在编译期就可以确定,方法运行期间不会改变。
  • 虚拟机通过索引定位的方式使用局部变量表。当调用方法是非静态方法时,局部变量表第0位索引默认是用于传递方法所属对象实例的引用,即“this”关键字指向的对象。
  1. 操作数栈
  • 操作数栈相当于工作区。
  • java虚拟机的解释执行引擎称为“基于栈的执行引擎”,这里的栈指的是操作数栈。
  1. 动态链接
  • 栈帧包含一个指向运行时常量池的引用。
  1. 方法出口
  • 方法出口包括正常完成出口和异常完成出口;
  • 方法返回时要执行的3个操作:(1)恢复上层方法的局部变量表和操作数栈;(2)将返回值压入调用者栈帧的操作数栈;(3)调整程序计数器的值以指向调用指令的后一条指令
  1. 定义了两种异常情况:
  • StackOverflowError异常:线程请求的栈深度大于虚拟机所允许的深度。(递归过深)
  • OutOfMemoryError异常:虚拟机在扩展栈时无法申请到足够的内存空间。

本地方法栈

  1. 作用与虚拟机栈相似,区别:虚拟机栈为java方法服务,本地方法栈为Native方法服务;
  2. Hotspot虚拟机将本地方法栈和虚拟机栈合二为一;
  3. 定义了两种异常情况:StackOverflowError和OutOfMemoryError。

java堆

  1. 线程共享;
  2. 存储对象实例和数组;
  3. 是垃圾收集器管理的主要区域,也称为“GC”堆;
  4. 定义了OutOfMemoryError异常。

方法区

  1. 线程共享;
  2. 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据;
  3. 方法区的回收目标主要是:类型卸载和常量池回收;
  4. 方法区也被称为“永久代”,主要是因为Hotspot虚拟机用永久代来实现方法区;
  5. 定义了OutOfMemoryError异常。
  6. 运行时常量池是方法区的一个部分,运行时常量池相对于class文件常量池具有两个特征:java虚拟机没有做任何细节的要求;具备动态性。

直接内存

  1. NIO类使用;
  2. 直接内存的分配不受java堆的限制,受本机总内存的限制;
  3. 配置虚拟机参数时,不要忽略直接内存,防止出现OutOfMemoryError。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值