JVM虚拟机

PC

  • 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。
  • 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。

存储固定长度的内存地址,所以不会发生OOM

虚拟机栈

存储方法的调用情况,每调用一个方法就要压入这个栈帧,调用结束弹出。
在这里插入图片描述

局部变量表

  • 存储方法的局部变量值和作用域。
  • 存储this指针,方法参数,方法内部的局部变量。
  • 当方法内部某个局部变量作用失效后,他所占据的slot可以被复用
  • int类型占一个slot,long类型占两个slot

操作数栈
存放计算中间结果和操作数

动态链接
当要调用其他类的方法的时候,需要将符号引用转换成对应的运行时常量池中的内存地址。动态链接就保存了编号到运行时常量池的内存地址映射关系。
方法返回地址

  • 方法返回后,PC怎么知道应该去哪里执行?这个就记录在栈帧里面。
  • 如果函数调用陷入无限循环的话,就会导致栈中被压入太多栈帧而占用太多空间,导致栈空间过深。那么当线程请求栈的深度超过当前 Java
    虚拟机栈的最大深度的时候,就抛出 StackOverFlowError 错误。
  • Java 方法有两种返回方式,一种是 return 语句正常返回,一种是抛出异常。不管哪种返回方式,都会导致栈帧被弹出。也就是说,栈帧随着方法调用而创建,随着方法结束而销毁。无论方法正常完成还是异常完成都算作方法结束。
  • 除了 StackOverFlowError错误之外,栈还可能会出现OutOfMemoryError错误,这是因为如果栈的内存大小可以动态扩展,如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

简单总结一下程序运行中栈可能会出现两种错误:

  • StackOverFlowError: 若栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前 Java虚拟机栈的最大深度的时候,就抛出StackOverFlowError 错误。
  • OutOfMemoryError: 如果栈的内存大小可以动态扩展,如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

本地方法栈
虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务,存储native本地方法的栈帧。 和 Java 虚拟机栈共用一个栈空间。

方法区

运行时常量池
存放类的基本信息,还有用于存放编译期生成的各种字面量(Literal)和符号引用(Symbolic Reference)的常量池表(Constant Pool Table) ,常量池表会在类加载后存放到方法区的运行时常量池中
字符串常量池
JDK7以前:运行时常量池包含字符串常量池一样被放在堆中永久代中
JDK7:字符串常量池被单独挪到了堆中,永久代中其他不变
JDK8:永久代被取消,取而代之的是直接内存的元空间,字符串常量池还在堆中。
JDK7以及之后的版本,intern方法字符串常量池只会存放
为什么取消永久代,放在直接内存的元空间?
主要是考虑到,永久代放在堆中很影响堆的垃圾回收效率,并且随着永久代越来越大,从未来角度来看,会很影响JVM的内存大小,如果放在直接内存中,方法区的内存就受本地系统影响。
为什么把字符串常量池单独挪到堆中?
字符串常量池中的常量经常会被回收,如果放在永久代,他被回收的概率很小,所以应该单独放在堆中,提高他的回收效率。

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值