白话说Java虚拟机原理系列【第六章】:内存结构之栈/寄存器/直接内存详解



前导说明:
本文基于《深入理解Java虚拟机》第二版和个人理解完成,
以大白话的形式期望能用大家都看懂的描述讲清楚虚拟机内幕,
后续会增加基于《深入理解Java虚拟机》第三版内容,并进行二个版本的对比

JAVA栈(Stack)

线程独享此区域。

它的生命周期与线程相同,描述的是Java方法执行的内存区域。即用来运行方法的地方。线程中调用任何一个方法都会在此区域创建一个栈帧用于存储局部变量表操作数栈动态链接方法返回地址等信息。每一个方法从调用直到执行完成,都对应着一个栈帧在JVM中入栈到出站的过程。当然出站后栈帧就会释放。

方法调用的字节码指令,就是由线程执行方法时发出的,这个在方法区-方发表章节已经讲过了,大家可以回顾一下。

  • 1.invokevirtual
  • 2.invokeinterface
  • 3.invokespecial
  • 4.invokestatic
  • 5.invokedynamic

线程调用方法创建栈帧的大小,或者说是栈帧中局部变量表的大小是确定的,因为线程调用方法时,是直接从方法区的对应的class文件的方法表的属性集合的code属性中直接把方法的字节码指令拿过来,而此部分在编译期就已经确定了大小了。且在整个方法运行过程中局部变量表的大小都不会改变。

异常:

  • 1.StackOverflowError:当线程请求的栈的深度大于虚拟机设定的深度,则会抛出此异常。
    可以通过动态扩展的配置来抵消此异常。
  • 2.OutOfMemoryError:如果可以动态扩展,但是扩展时无法申请到足够的内存,就会抛出此异常。
本地方法栈

线程独享此区域。

用于调用native本地方法时使用。其他和虚拟机栈(Java栈)基本一样。

寄存器(程序计数器)

线程独享此区域。

用于保存将线程要执行的下一条指令地址。

之所以要线程独享,因为JVM的多线程实际是靠上下文切换,即cpu处理器切换来实现不同线程的轮询执行的,实际上一个时刻还是执行的一个线程,那么不同的线程有不同的运行进度,为了能中断后恢复线程的正确执行状态,必须保障每个线程都要有自己的寄存器,这样恢复后才能各自从各自的状态继续执行。

异常:
该内存区域JVM规范中指定不会出现OutOfMemoryError错误。

直接内存

直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。但是这部分内存也被频繁的使用,而且也可能导致OutOfMemoryError异常出现。

分析一下书中的这段直接内存的描述,就是直接内存占用的是机器物理内存的某一块内容,而我们物理内存会通过逻辑划分分成用户空间和内核空间,拿32位操作系统而言,最大支持4G内存,那么其中1G会作为内核空间,另外3G作为用户空间,内核空间多数用来执行系统内核的指令运行,而用户空间一般运行第三方应用程序或我们自己开发的程序。而我们JVM当然就运行在用户空间了,那么用户空间和内核空间又是什么东西?我们在读取磁盘内容到内存的过程需要使用io,而io又分为标准io和直接io,我们一般都是用标准io,即磁盘的内容先进入内核空间,然后由内核空间拷贝到用户空间,即一次读取要经过2次拷贝,这个我们在nio章节会详细讲解,此处暂时了解下。

既然IO中会有2个步骤的文件拷贝,即磁盘到内核空间,内核空间到程序用户空间。在nio章节我们会提到实现nio的epoll方法的实现中他会创建一个mmap来保存数据,而mmap占用的内存是比较特殊的,它是内核空间和用户空间共用的一块内存区域,也即mmap的数据即在内核空间也在用户空间,那么从io的角度他就不需要从内核空间拷贝到用户空间,也就是说省略了一步拷贝,换句话说从磁盘读取过来的数据可以直接操作了,而这个mmap占用的内存就是直接内存。在nio中我们也可以通过特殊的api来在直接内存中创建一个字符数据ByteBuffer用来读入/读出数据。

注意:虽然直接内存不占堆内存,但是他也会占用物理内存,所以特别是使用nio操作的程序,一定要注意不要忽略这个区域的内存分配,否则出问题不好排查。另外直接内存因为是在堆外的空间,所以不会被gc垃圾收集管理,而此处的管理需要单独进行,可以通过api来管理,具体我们在讲nio时会讲到。

配置:可以通过-XX:MaxDirectMemorySize指定分配大小,不指定默认与java堆最大值(-Xmx)一样大。注意分配内存的时候不要忽略掉这个。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

上树的蜗牛儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值