深入理解JVM(2)——运行时数据区
1、运行时数据区
1.1、程序计数器
记录当前线程正在执行的字节码指令的地址,如果正在执行的是 Native 方法,这个计数器值则为空。
1.2、虚拟机栈
每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、 动态链接、 方法返回地址等信息。方法调用到执行完成的过程,就对应一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
可以通过虚拟机参数 -Xss 来指定每个线程的虚拟机栈内存大小: -Xss128k
该区域可能抛出以下异常:
- 当线程请求的栈深度超过最大值,会抛出 StackOverflowError 异常;
- 栈进行动态扩展时如果无法申请到足够内存,会抛出 OutOfMemoryError 异常。
1.2.1、局部变量表
是一片逻辑连续的内存空间,最小单位是Slot,用来存放方法参数和方法内部定义的局部变量。虚拟机通过索引定位的方式使用局部变量表,索引值范围从0开始至局部变量表最大的Slot数量。
虚拟机没有明确指明一个Slot的内存空间大小。但是boolean、byte、char、short、int、float、reference、returnAddress类型的数据都可以用32位空间或更小的内存来存放。这些类型占用一个Slot。Java中的long和double类型是64位,占用两个Slot。(只有double和long是jvms里明确规定的64位数据类型)
reference类型:表示对一个对象实例的引用,它可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置。通过这个引用至少做到两点,一是从此引用能查找到对象在Java堆中的数据存放的起始地址索引,二是从此引用能查找到对象所属数据类型在方法区中的存储的类型信息。
returnAddress类型:指向了一条字节码指令的地址。
执行实例方法,局部变量表中第0位索引的Slot默认是方法所属对象实例的引用,方法中可以通过关键字“this”来访问。 方法参数则按照参数表顺序,占用从1开始的局部变量Slot。之后再根据方法体内部定义的变量顺序和作用域分配其余的Slot。
1.2.2、操作数栈
每个栈帧都包含一个叫做操作数栈(操作栈)的后进先出的栈。
方法刚开始执行时,这个方法的操作数栈是空的,在方法的执行过程中,有各种字节码指令往操作数栈中写入和提取内容,也就是出栈/入栈操作。向其他方法传参的参数,也存在操作数栈中。其他方法返回的结果,返回时存在操作数栈中。
操作数栈中元素的数据类型必须与字节码指令的序列严格匹配。
本来栈桢作为虚拟机栈的一个单元,应该是栈桢之间完全独立的。但是,大多虚拟机的实现里进行了一些优化:为了避免过多的方法间参数的复制传递、方法返回值的复制传递等一些操作,就让一部分数据进行栈桢间共享。
1.2.3、动态链接
Class 文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或者第一次使用的时候就转化为直接引用,这种转化称为静态解析。另外一部分将在每一次运行期间转化为直接引用,这部分称为动态连接。
1.2.4、方法返回地址
当一个方法被执行后有两种方式退出这个方法:
- 正常完成出口:执行引擎遇到任意一个方法返回的字节码指令。
- 异常完成出口:遇到异常,并且这个异常没有在方法体里得到处理。
无论采用何种退出方式,在方法退出后,都需要返回方法被调用的位置,程序才能继续执行。方法返回时可能需要在栈帧中保存一些信息,用于恢复它的上层方法的执行状态。一般来说方法正常退出,调用者的 PC 计数器的值就可作为返回地址,栈帧中很可能保存的就是这个计数器的值。而方法异常退出时,返回地址要通过异常处理器来确定,这时候栈帧中一般不会保存这部分信息。
方法退出的过程实际上等同于将当前栈帧出栈。因此退出时的操作可能有:恢复上层方法的局部变量表和操作数栈,如果有返回值则把他压入调用者栈帧的操作数栈中。调整 PC 计数器的值以指向方法调用的指令的后一条指令。
1.3、本地方法栈
本地方法栈与 Java 虚拟机栈类似,它们之间的区别只不过是本地方法栈为本地方法服务。
1.4、堆
所有对象都在这里分配内存,是垃圾收集的主要区域("GC 堆")。
现代的垃圾收集器基本都是采用分代收集算法,其主要的思想是针对不同类型的对象采取不同的垃圾回收算法,可以将堆分成两块:
- 新生代(Young Generation)
- 老年代(Old Generation)
堆不需要连续内存,并且可以动态增加其内存,增加失败会抛出 OutOfMemoryError 异常。
可以通过 -Xms 和 -Xmx 两个虚拟机参数来指定一个程序的堆内存大小,第一个参数设置初始值,第二个参数设置最大值。
1.5、方法区
用于存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
和堆一样不需要连续的内存,并且可以动态扩展,动态扩展失败一样会抛出 OutOfMemoryError 异常。
对这块区域进行垃圾回收的主要目标是对常量池的回收和对类的卸载,但是一般比较难实现。
HotSpot 虚拟机把它当成永久代来进行垃圾回收。但是很难确定永久代的大小,因为它受到很多因素影响,并且每次 Full GC 之后永久代的大小都会改变,所以经常会抛出 OutOfMemoryError 异常。为了更容易管理方法区,从 JDK 1.8 开始,移除永久代,并把方法区移至元空间,它位于本地内存中,而不是虚拟机内存中。
1.5.1、运行时常量池
运行时常量池是方法区的一部分。
Class 文件中的常量池(编译器生成的各种字面量(Literal)和符号引用)会在类加载后被放入这个区域。
除了在编译期生成的常量,还允许动态生成,例如 String 类的 intern()。
1.6、直接内存
在 JDK 1.4 中新加入了 NIO 类,它可以使用 Native 函数库直接分配堆外内存(Native 堆),然后通过一个存储在 Java 堆里的 DirectByteBuffer 对象作为这块内存的引用进行操作。
这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆中来回复制数据。
2、元空间替换永久代
在JDK1.7及以前版本的 HotSpot 虚拟机中,是采用永久代(PermGen space)来实现 JVM 规范中的方法区的。到了JDK1.8方法区的实现变成了元空间(Metaspace)。
其实,移除永久代的工作从JDK1.7就开始了。JDK1.7中,存储在永久代的部分数据就已经转移到了Java Heap或者是 Native Heap。但永久代仍存在于JDK1.7中,并没完全移除,譬如符号引用转移到了 native heap;字面量、类的静态变量转移到了java heap。
2.1、为什么移除持久代
- 它的大小是在启动时固定好的——很难进行调优。-XX:MaxPermSize,指定太小容易造成永久代OOM。
- 永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
- Oracle 可能会将HotSpot 与 JRockit 合二为一。
2.2、元空间配置参数
-XX:MetaspaceSize=N
这个参数是初始化的Metaspace大小,该值越大触发Metaspace GC的时机就越晚。随着GC的到来,虚拟机会根据实际情况调控Metaspace的大小,可能增加上线也可能降低。在默认情况下,这个值大小根据不同的平台在12M到20M浮动。使用java -XX:+PrintFlagsInitial命令查看本机的初始化参数,-XX:Metaspacesize为21810376B(大约20.8M)。
-XX:MaxMetaspaceSize=N
这个参数用于限制Metaspace增长的上限,防止因为某些情况导致Metaspace无限的使用本地内存,影响到其他程序。在本机上该参数的默认值为4294967295B(大约4096MB)。
-XX:MinMetaspaceFreeRatio=N
当进行过Metaspace GC之后,会计算当前Metaspace的空闲空间比,如果空闲比小于这个参数,那么虚拟机将增长Metaspace的大小。在本机该参数的默认值为40,也就是40%。设置该参数可以控制Metaspace的增长的速度,太小的值会导致Metaspace增长的缓慢,Metaspace的使用逐渐趋于饱和,可能会影响之后类的加载。而太大的值会导致Metaspace增长的过快,浪费内存。
-XX:MaxMetasaceFreeRatio=N
当进行过Metaspace GC之后, 会计算当前Metaspace的空闲空间比,如果空闲比大于这个参数,那么虚拟机会释放Metaspace的部分空间。在本机该参数的默认值为70,也就是70%。
-XX:MaxMetaspaceExpansion=N
Metaspace增长时的最大幅度。在本机上该参数的默认值为5452592B(大约为5MB)。
-XX:MinMetaspaceExpansion=N
Metaspace增长时的最小幅度。在本机上该参数的默认值为340784B(大约为330KB)。
深入理解JVM(2)——运行时数据区的更多相关文章
- JVM入门——运行时数据区
这张图我相信基本上对JVM有点接触的都应该很熟悉,可以说这是JVM入门的第一课.其中的“堆”和“虚拟机栈(栈)”更是耳熟能详.下面将围绕这张图对JVM的运行时数据区做一个简单介绍. 程序计数器(Pro ...
- JVM虚拟机-运行时数据区概述
目录 运行时数据区域 总览 概念扫盲 什么是栈帧(Stack Frame) JVM常见出现两种错误 程序计数器 虚拟机栈 结构 局部变量表 方法是如何调用的 本地方法栈 堆 浅堆和深堆 堆的细分 方法 ...
- jvm理论-运行时数据区
三大流行jvm sun HotSpot ibm j9 BEA JRockit Oracle 会基于HotSpot整合 JRockit. jvm运行时数据区 java虚拟机所管理的内存将会包括以下几个运 ...
- JVM之运行时数据区
Java虚拟机运行时数据区包括PC寄存器.Java虚拟机栈.Java堆.方法区.本地方法栈.运行时常量池六个部分. 1. PC寄存器 PC寄存器(又叫程序计数器,Program Counter Reg ...
- 深入理解Java虚拟机&运行时数据区
其中,程序计数器.虚拟机栈.本地方法栈3个区域随线程而生,随线程而灭.
- 【JVM第四篇--运行时数据区】堆
写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 一.堆的概述 JVM的运行时数据区如下: 一个Java程序运行起来对应着一个进程(操 ...
- 【转】Java运行时数据区简介及堆与栈的区别
理解JVM运行时的数据区是Java编程中的进阶部分.我们在开发中都遇到过一个很头疼的问题就是OutOfMemoryError(内存溢出错误),但是如果我们了解JVM的内部实现和其运行时的数据区的工作机 ...
- Java 运行时数据区
写在前面 本文描述的有关于 JVM 的运行时数据区是基于 HotSpot 虚拟机. 概述 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以 ...
- 面试常问的 Java 虚拟机运行时数据区
写在前面 本文描述的有关于 JVM 的运行时数据区是基于 HotSpot 虚拟机. 概述 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以 ...
随机推荐
- 对国内AR产业的预言
先丢预言,国内任何AR公司,包含几大块,医疗行业.手机制造商和自动驾驶,倘若没有能力进行系统设计,最后都要死,或者裁掉业务. AR本身不会演化为独立的业务,而是作为辅助性的工具进入传统已经存在的部门之 ...
- 牛客网:Java重命名文件
项目介绍 不管是C/C++还是JAVA,都可能生成一些持久性数据,我们可以将数据存储在文件或数据库中,此项目主要训练学习Java对本地磁盘的文件重命名,例如C:\nowcoder.txt重命名C:\n ...
- dede后台删除文章后台还有分页显示解决方法
打开dede目录中content_list.php 大概在100行左右 $sql = "SELECT COUNT(*) AS dd FROM `#@__arctiny` $tinyQuery ...
- MySQL慢查询日志释疑总结
之前写了一篇"MySQL慢查询日志总结",总结了一些MySQL慢查询日志常用的相关知识,这里总结一下在工作当中遇到关于MySQL慢查询日志的相关细节问题,有些是释疑或自己有疑惑 ...
- 导入JavaWeb 项目出现的问题
前言: 环境: windown 10 JDK 1.8 Tomcat 7 eclipse 导入项目 下面错误是出现的问题 Multiple annotations found at this line: ...
- ueditor富文本编辑器使用百度地图自定义动态地图组件及兼容https及http协议
ueditor富文本编辑器默认支持百度地图组件,但是如果导入动态地图后会加很多默认的地图组件在上面.如果需要自定义动态地图的组件则需要修改ueditor特定的html. ueditor百度地图组件所在 ...
- js字符串String提取方法比较
JavaScript: Slice, Substring, or Substr的选择! 在JavaScript中,字符串主要通过以下String方法之一提取: // slice // syntax: ...
- Java使用volatile实现多线程输出ABC共10次
问题 有A,B,C三个线程, A线程输出A, B线程输出B, C线程输出C.要求,同时启动三个线程, 按顺序输出ABC, 循环10次. 今天在写多线程的时候找例子,见到了这样一个题,觉得不难,但是在网 ...
- vue 组件中的钩子函数 不能直接写this
export default { data(){ return { num: 18 } }, beforeRouteEnter(to, from, next){ next(vm=>{ vm.nu ...
- Vmware10中Centos7挂载Windows主机的共享文件夹,提示:Error: cannot mount filesystem: No such device
1.设置共享权限 2.安装VMware tools 点击虚拟机 点击安装 VMware tools 将/run/media/zhaojq/VMware\ Tools 目录下的VMwareTools-9 ...