JVM运行时数据区


theme: qklhk-chocolate

参考:

https://www.jianshu.com/p/0a1e0e410edf

https://blog.csdn.net/weixin_39941620/article/details/114164209

https://zhuanlan.zhihu.com/p/161994662

JDK1.8 运行时数据区

按线程调用划分为:

  • 线程公有:堆、方法区、直接内存(非运行时内存一部分)、元数据
  • 线程私有:虚拟机栈、本地方法栈、程序计数器

注:运行时数据区在 HotSpot 1.8之前的版本和1.8版本有所不同,将方法区移动到元空间

img

堆 Heap

概述

JVM中只存在一个堆内存空间,被所有线程共享,所有类的实例和数组的内存都存放在堆区中,是虚拟机中最大的内存区域,同时也是垃圾回收的主要区域

堆内存分配

堆在Java虚拟机启动时创建,大小可固定,也可伸缩;堆内存不需要连续空间

  • -Xms:JVM初始分配堆内存,默认是物理内存的1/64
  • -Xmx:JVM最大分配堆内存,默认是物理内存的1/4
  • 如果-Xmx不指定或者指定偏小,可能会导致OutOfMemoryError错误,此错误来自JVM,无法被try...catch捕捉

堆内存回收

image.png

堆空间大小 = 新生代 + 老年代,默认新生代:老年代=1:2

方法区 -> 元空间 Meta Space

image.png

  • 方法区:JDK1.8之前存放被虚拟机加载的类信息、常量、静态变量、动态生成的类
  • 元空间:线程共用,使用直接内存,并不在虚拟机中,GC不管理元空间的内存

注:本机直接内存的分配不会受到 Java 堆的限制,但是,既然是内存就会受到本机总内存大小以及处理器寻址空间的限制。

程序计数器 Program Counter Register

程序计数器是一块很小的内存区域,可以当成当前线程所执行的字节码的行号指示器,字节码解释器通过改变计数器的值来选取下一条指令。依赖程序计数器的功能:循环、异常处理、线程恢复等。

  1. 每个线程都私有一个程序计数器,保证线程切换后恢复到正确的执行位置
  2. 线程执行Native方法,计数器为空
  3. 线程执行Java方法,计数器记录正在执行的虚拟机字节码指令的地址
  4. 唯一一个没有定义OutOfMemoryError的区域,生命周期与线程绑定

栈 Stack

虚拟机栈是线程私有的,生命周期与线程一致。虚拟机栈中的栈元素叫做栈帧(Stack Frame),栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构,每一个方法从调用开始至执行完成都对应着一个栈帧在虚拟机栈中由入栈到出栈的过程。

方法出栈的场景包括:return语句、抛出异常

每个栈帧包括以下信息:

  • 局部变量表:存放编译期间可知的数据类型(基本类型)、对象引用(reference)
  • 操作数栈
  • 动态链接
  • 方法返回地址
  • ... ...

栈的特点:

  1. 局部变量表所需要的内存空间在编译期间确定并分配
  2. 方法运行期间不改变局部变量表的大小
  3. 如果虚拟机栈的内存大小不允许动态扩容,那么当请求的栈深度大于虚拟机允许的深度,抛出StackOverflowError
  4. 如果虚拟机栈的内存大小允许动态扩容,虚拟机栈扩展时内存不足,抛出OutOfMemoryError

本地方法栈 Native Method Stack

本地方法栈功能与虚拟机栈类似,区别是:虚拟机栈为虚拟机执行Java方法(字节码)服务,本地方法栈为Native方法服务

本地方法被执行时,本地方法栈会创建一个栈帧,同样存放该本地方法的:局部变量表、操作数栈、动态链接、出口信息等。

了解Native方法

Native Method:是一个Java调用非Java代码的接口,一个Native Method表示该方法的实现由非Java语言实现。

VM怎样使Native Method跑起来:当一个类第一次被使用到时,这个类的字节码会被加载到内存,并且只会回载一次。在这个被加载的字节码的入口维持着一个该类所有方法描述符的list,这些方法描述符包含这样一些信息:方法代码存于何处,它有哪些参数,方法的描述符(public之类)等等。如果一个方法描述符内有native,这个描述符块将有一个指向该方法的实现的指针。这些实现在一些DLL文件内,但是它们会被操作系统加载到java程序的地址空间。当一个带有本地方法的类被加载时,其相关的DLL并未被加载,因此指向方法实现的指针并不会被设置。当本地方法被调用之前,这些DLL才会被加载,这是通过调用java.system.loadLibrary()实现的。

运行时常量池

运行时常量池是方法区的一部分。

JDK1.8 hotspot 移除了永久代用元空间(Metaspace)取而代之,这时候字符串常量池还在堆, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间(Metaspace)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值