JVM-运行时数据区

发布于:2025-02-10 ⋅ 阅读:(29) ⋅ 点赞:(0)

JVM的组成
在这里插入图片描述

运行时数据区-总览

Java虚拟机在运行Java程序过程中管理的内存区域,称之为运行时数据区。
《Java虚拟机规范》中规定了每一部分的作用
在这里插入图片描述
运行时数据区-应用场景
Java的内存分成哪几部分?
Java内存中哪些部分会内存溢出?
JDK7 和JDK8中在内存结构上的区别是什么?
内存调优
在这里插入图片描述

一、运行时数据区-程序计数器

程序计数器(Program Counter Register)也叫PC寄存器,每个线程会通过程序计数器记录当前要执行的字节码指令的地址。
在这里插入图片描述
作用
1、可以控制程序指令的进行,实现分支、跳转、异常等逻辑。
2、在多线程执行情况下,Java虚拟机需要通过程序计数器记录CPU切换前解释执行到哪一句指令并继续解释运行。
程序计数器在运行时会出现内存溢出吗?
内存溢出指的是程序在使用某一块内存区域时,存放的数据需要占用的内存大小超过了虚拟机能提供的内存上限。
因为每个线程只存储一个固定长度的内存地址,程序计数器是不会发生内存溢出的。
程序员无需对程序计数器做任何处理。

二、栈

Java虚拟机栈和本地方法栈。:Java虚拟机栈存储了Java方法调用时的栈帧,而本地方法栈存储的是native本地方法的栈帧。

Java虚拟机栈用来保存java中实现的方法,每次请求方法都会往栈里进行保存。而本地方法栈存储的是native本地方法的栈帧。
采用栈的数据结构来管理方法调用中的基本数据,先进后出(First In Last Out),每一个方法的调用使用一个栈帧(Stack Frame)来保存。
Java虚拟机栈随着线程的创建而创建,而回收则会在线程的销毁时进行。由于方法可能会在不同线程中执行,每个线程都会包含一个自己的虚拟机栈。
在这里插入图片描述
局部变量表的作用是在方法执行过程中存放所有的局部变量。编译成字节码文件时就可以确定局部变量表的内容。
操作数栈是栈帧中虚拟机在执行指令过程中用来存放中间数据的一块区域。他是一种栈式的数据结构,如果一条指令将一个值压入操作数栈,则后面的指令可以弹出并使用该值。
在编译期就可以确定操作数栈的最大深度,从而在执行时正确的分配内存大小。
帧数据当前类的字节码指令引用了其他类的属性或者方法时,需要将符号引用(编号)转换成对应的运行时常量池中的内存地址。动态链接就保存了编号到运行时常量池的内存地址的映射关系。
方法出口指的是方法在正确或异常结束时,当前栈帧会被弹出,同时程序计数器应该指向上一个栈帧中的下一条指令的地址。所以在当前栈帧中,需要存储此方法出口的地址。
异常表存放的是代码中异常的处理信息,包含了异常捕获的生效范围以及异常发生后跳转到的字节码指令位置。

Java虚拟机栈-栈内存溢出
Java虚拟机栈如果栈帧过多,占用内存超过栈内存可以分配的最大大小就会出现内存溢出。
Java虚拟机栈内存溢出时会出现StackOverFlowError的错误。
在这里插入图片描述
Java虚拟机栈-默认大小
如果我们不指定栈的大小,JVM将创建一个具有默认大小的栈。大小取决于操作系统和计算机的体系结构。
要修改Java虚拟机栈的大小,可以使用虚拟机参数 -Xss
语法: -Xss栈大小
单位: 字节(默认,必须是1024的倍数)、k或者K(KB)、m或者M(MB)、g或者G(GB)。
-Xss1024k,
Java虚拟机栈-注意事项
1、HotSpot JVM对栈大小的最大值和最小值有要求:
比如测试如下两个参数:
-Xss1k
-Xss1025m
Windows(64位)下的JDK8测试最小值为180k,最大值为1024m。
2、局部变量过多、操作数栈深度过大也会影响栈内存的大小。
一般情况下,工作中即便使用了递归进行操作,栈的深度最多也只能到几百,不会出现栈的溢出。所以此参数可以手动指定为-Xss256k节省内存。

本地方法栈
Java虚拟机栈存储了Java方法调用时的栈帧,而本地方法栈存储的时native本地方法的栈帧。
在HotSpot虚拟机中,Java虚拟机栈和本地方法栈实现上使用了同一个栈空间。本地方法栈会在栈内存上生成一个栈帧,临时保存方法的参数同时方便出现异常时也把本地方法的栈信息打印出来。
在这里插入图片描述

三、堆

一般Java程序中堆内存是空间最大的一块内存区域,创建出来的对象都存在堆上。
栈上的局部变量表中,可以存放堆上对象的引用。静态变量也可以存放堆对象的引用,通过静态变量就可以实现对象在线程之间共享。
堆空间有三个需要关注的值,used、total、max
used指的是当前已使用的堆内存,total是java虚拟机已经分配的可用堆内存,max是java虚拟机可以分配的最大堆内存。
在这里插入图片描述
arthas堆内存相关的功能
堆内存used total max 三个值可以通过dashboard命令看到
手动指定刷新频率(不指定默认5秒一次):dashboard -i刷新频率(毫秒)
堆-设置大小
要修改堆的大小,可以试用虚拟机参数-Xmx(max最大值)和-Xms(初始的total)
语法:-Xmx值 -Xms值
单位:字节(默认,必须是1024的倍数)、k或者K(KB)、m或者M(MB)、g或者G(GB)
限制:Xmx必须大于 2 MB,Xms必须大于1MB
Java服务端程序开发时,建议将-Xmx 和-Xms设置为相同的值,这样在程序启动之后可以使用的总内存就是最大内存,而无需向java虚拟机再次申请,减少了申请并分配内存时间上的开销,同时也不会出现内存过剩之后堆收缩的情况。

-Xmx具体设置的值与实际的应用程序运行环境有关。

四、方法区

方法区是线程共享区,方法区存放基础信息的位置,线程共享,主要包含三部分内容:
类的元信息(保存所有类的基本信息)、运行时常量池(保存了字节码文件中的常量池内容)、字符串常量池(保存了字符串常量)。
在这里插入图片描述
1、方法区是用来存储每个类的基本信息(元信息),一般称之为InstanceKlass对象。在类的加载阶段完成。
在这里插入图片描述
2、方法区除了存储类的元信息之外,还存放了运行时常量池。常量池中存放的是字节码中的常量池内容。
字节码文件中通过编号查表的方式找到常量,这种常量池称为静态常量池。当常量池加载到内存中后,可以通过内存地址快速的定位到常量池中的内容,这种常量池称为运行时常量池。
在这里插入图片描述
方法区是《Java虚拟机规范》中设计的虚拟概念,每款Java虚拟机在实现上都各不相同。Hotspot设计如下:
JDK7及之前的版本将方法区放在堆区域中的永久代空间,堆的大小由虚拟机参数控制。
JDK8及之后的版本将方法区存放在元空间中,元空间位于操作系统维护的直接内存中,默认情况下只要不超过操作系统承受的上限,可以一致分配。
在这里插入图片描述

五、直接内存


网站公告

今日签到

点亮在社区的每一天
去签到