《深入理解JAVA虚拟机》(一) JVM 结构 + 栈帧 详解
1、程序计数器(Program Counter Register)
线程独有,每个线程都有自己的计数器;由于CPU的任意时刻只能执行所有线程中的一条,所以需要使用程序计数器来支持JVM的并发;另外字节码解释器读取下一行指令、分支、循环、跳转、异常处理等等逻辑都依赖于程序计数器。程序计数器是JVM唯一不存在OutOfMemoryError的区域。
2、Java虚拟机栈(Java Virtual Machine Stacks)
线程独有,用于保存线程相关的栈帧(@注释1);生命周期与线程相同,线程中,方法执行的过程等同该方法对应栈帧从入栈到出栈的过程,如果方法执行过程中调用了其它方法,那么同样的道理,方法内部调用的其它方法的栈帧也会入栈,以此类推,直到当前方法执行完,然后从虚拟机栈中出栈即代表一个方法完整的执行过程。
Java虚拟机栈内存大小即可固定,也支持动态拓展(在JVM运行内存的范围内):
(1)当固定大小情况下,线程请求分配的栈容量大于Java虚拟机栈最大容量时,抛出异常:StackOverFlowError。
(2)当可拓展时,如果在拓展过程中,无法申请到足够的内存时,抛出异常:OutOfMemoryError(比如:JVM运行内存被占满,此时已经无处可以申请内存了)。
3、本地方法栈(Native Method Stack)
类似上述Java虚拟机栈,放入Java虚拟机栈中的是Java方法的栈帧;而本地方法栈中的内容是native方法(@注释2)的栈帧,他为native方法服务。
例如:java.lang.String.intern() 和 java.lang.Object.hashCode()方法的定义如下:
public native String intern();
public native int hashCode();
4、Java堆(Java Heap)
Java堆是线程共享的,它是JVM中占用内存空间最大的部分,它的作用是存放Java对象实例,几乎所有的Java对象都从堆中分配内存;因为Java堆存放了大量对象实例,所以这里也是垃圾回收发生的主要场所;Java堆内存大小即可设为固定值,也可以动态拓展,Java堆可以处于非连续的物理内存上(大学的某门课讲过原理,逻辑上连续即可)。
5、方法区(Method Area)
(1) 基本概念:同Java堆,方法区也是线程共享;方法区保存JVM加载的:类的信息、常量、静态变量、即时编译器编译后的代码,等数据;Java虚拟机规划中对方法区限制较少,是否受垃圾回收器管理是可选的,大小可固定或可拓展,可以存在于不联系的内存空间上。
(2) 关于HotSpot虚拟机:Java 7之前,方法区与Java堆共享内存,Java堆被划分为:青年代、老年代、永久代,其中永久代即指方法区,同样此时方法区被垃圾回收器管理;到了Java 8,HotSpot虚拟机改变了实现方式,方法区分配的内存被移至虚拟机外,此时称呼其为元空间,不再与Java堆共享内存,也不再被垃圾回收器管理。
(3) 运行时常量池
a 基本概念:位于方法区,它是每一个类或接口中的,常量池表,运行时的表示形式;每一个运行时常量池(对应 类/接口),在加载 类/接口时被创建并分配到方法区中。
b 常量池作用:存放编译器生成的字面量和符号引用,当虚拟机运行时,从常量池获取字面量或者符号引用,在类创建或者运行时,映射到具体的内存中。
c 字面量(常量):字符串 || final 变量
d 符号引用:类/接口的全限定名 || 字段名称及其描述符 || 方法名称及其描述符
本文仅限于JVM各个组成部分即基本介绍,不深入讨论原理,旨于深入探究JVM前建立相关概念模型。
* 拓展及注释
1、栈帧
基本概念:在JAVA虚拟机栈中使用,用于支持JVM进行方法调用和方法执行的数据结构(栈帧就是虚拟栈中的一个元素),每个方法执行时都会创建一个栈帧,它包括:局部变量表、操作数栈、动态链接、方法返回地址等。对于JVM执行引擎来说,在活动的线程中,只有处于栈顶的栈帧是有效的,所有字节码指令都只对作用在当前栈帧关联的方法上。
(1)局部变量表:一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量,局部变量表的容量以 变量槽(Slot) 为单位;每个Slot的大小与JVM平台有关,一般可以存放32位以内的数据类型:8种基本数据类型,以及 对象应用(reference)和returnAddress(方法返回地址)。对于 对象应用(reference),JVM必须做到能够直接或间接查找到对象在JAVA堆中的数据存储地址起始索引,以及能查找到对象所属数据类型在方法区中存储的类型信息;
(2)操作数栈:它是一个LIFO栈,操作数栈中的每一个元素都可以是任意的Java数据类型,栈的最小容量单位为32bite,32位的数据类型栈一个容量单位,64位数据类型占2个容量单位。JVM引擎执行的实质可以理解成:从操作数栈栈顶提取元素,然后执行指令,并把执行结果压入栈中的过程。
(3)动态链接:
前提条件(背景):每一个栈帧都会持有一个指向运行时常量池中该栈帧所属的方法引用,持有该引用的目的是为了支持方法调用过程中的动态链接。字节码(Class文件中,可以借助工具查看编译后的Class文件中的字节码指令) 的方法调用指令就是以Class文件常量池中的符号引用作为参数的;
动态链接:上述符号引用中,有的符号引用会在每次运行期间转化为直接引用,该类引用称为动态链接;
静态链接:相较于动态链接,对于静态链接,符号引用会在类加载 或 第一次使用的时候就转化为直接引用,而不是每次执行时去转化为直接引用。
(4)方法返回地址:方法执行完有两种方式退出方法,其一为方法执行过程中遇到任意一个方法返回的字节码指令,然后将相关结果返回给方法的调用者。其二,方法执行碰到异常,并且异常没有被捕获处理时推出方法。方法退出,即代表当前 (栈)帧 出栈,后续将会执行当前方法的调用者(上层方法)所对应的 (栈)帧 后续指令,那么对应的操作即为:恢复调用者对应 栈帧 的局部变量表和操作数栈,把当前方法的返回值压入调用者方法对应栈帧的操作数栈中,调用PC计数器的值并使之执行当前方法调用指令的下一条指令(当前方法执行完,挫骨扬灰,只留下了舍利供调用者使用,当然也可能直接烧成灰了啥也没有(无返回值))。
2、native方法(本地方法):
可以理解为java调用非Java代码实现的方法,的接口。众所周知,Java中很多东西都是其它语言实现的(例如C语言),使用native方法(本地方法)的原因如下:
(1)与java环境外交互:
有时java应用需要与java外面的环境交互。这是本地方法存在的主要原因,你可以想想java需要与一些底层系统交换信息时的情况。本地方法正是这样一种交流机制:它为我们提供了一个非常简洁的接口,而且我们无需去了解java应用之外的繁琐的细节。
(2)与操作系统交互:
JVM支持着java语言本身和运行时库,它是java程序赖以生存的平台,它由一个解释器(解释字节码)和一些连接到本地代码的库组成。然而不管怎 样,它毕竟不是一个完整的系统,它经常依赖于一些底层(underneath在下面的)系统的支持。这些底层系统常常是强大的操作系统。通过使用本地方法,我们得以用java实现了jre的与底层系统的交互,甚至JVM的一些部分就是用C写的,还有,如果我们要使用一些java语言本身没有提供封装的操作系统特性时,我们也需要使用本地方法。
《深入理解JAVA虚拟机》(一) JVM 结构 + 栈帧 详解的更多相关文章
- 【转载】深入理解Java虚拟机笔记---运行时栈帧结构
栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区的虚拟机栈(Virtual Machine Stack)的栈元素.栈帧存储了方法的局部变量表,操作 ...
- 深入理解java虚拟机(八)类加载过程详解
类从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading).验证(Verification).准备(Preparation).解析(Resolution).初始化(In ...
- 《深入理解Java虚拟机:JVM高级特性与最佳实践》【PDF】下载
<深入理解Java虚拟机:JVM高级特性与最佳实践>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062566 内容简介 作为一位 ...
- 读书笔记-《深入理解Java虚拟机:JVM高级特性与最佳实践》
目录 概述 第一章: 走进Java 第二章: Java内存区域与内存溢出异常 第三章: 垃圾收集器与内存分配策略 第四章: 虚拟机性能监控与故障处理 第五章: 调优案例分析与实战 第六章: 类文件结构 ...
- Java中堆内存和栈内存详解2
Java中堆内存和栈内存详解 Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,ja ...
- 深入理解Java虚拟机之JVM垃圾回收随笔
1.对象已经死亡? 1.1引用计数法:给对象中添加一个引用计数器,每当有一个地方引用他时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器都为0的对象就是不可能再被使用 的.但是它很难解决 ...
- Java 虚拟机系列二:垃圾收集机制详解,动图帮你理解
前言 上篇文章已经给大家介绍了 JVM 的架构和运行时数据区 (内存区域),本篇文章将给大家介绍 JVM 的重点内容--垃圾收集.众所周知,相比 C / C++ 等语言,Java 可以省去手动管理内存 ...
- java虚拟机规范-运行时栈帧
前言 java虚拟机是java跨平台的基石,本文的描述以jdk7.0为准,其他版本可能会有一些微调. 引用 java虚拟机规范 java虚拟机规范-运行时数据区 java内存运行时的栈帧结构 java ...
- 深入理解Java虚拟机:JVM高级特性与最佳实践
第一部分走近Java第1章走近Java21.1概述21.2Java技术体系31.3Java发展史51.4Java虚拟机发展史91.4.1SunClassicExactVM91.4.2SunHotSpo ...
- 深入理解Java虚拟机之JVM内存布局篇
内存布局**** JVM内存布局规定了Java在运行过程中内存申请.分配.管理的策略,保证了JVM的稳定高效运行.不同的JVM对于内存的划分方式和管理机制存在部分差异.结合JVM虚拟机规范,一起来 ...
随机推荐
- [转帖]tidb-系统内核调优及对比
一.背景 验证系统调优对性能的影响,用sysbench做了一些简单的测试,具体调整方法可见官方文档 二.特殊说明 1.透明大页查看 # 查看透明大页是否开启,[]在always处表示开启,[]在nev ...
- [转帖]服务注册与发现:Nacos Discovery
目录 一.概述 二.Nacos discovery--服务的注册与发现 1. 版本关系 2. 下载安装 (1)下载 (2)启动 (3)浏览器访问 三.Nacos服务注册与发现实战 1. 构建Sprin ...
- [转帖]线上Java 高CPU占用、高内存占用排查思路
一.前言 处理过线上问题的同学基本上都会遇到系统突然运行缓慢,CPU 100%,以及Full GC次数过多的问题.当然,这些问题的最终导致的直观现象就是系统运行缓慢,并且有大量的报警.本文主要针对系统 ...
- 一次典型的Memroy Leak的跟踪学习过程
背景 周四时某项目在QQ群里说自己的系统出现了CPU占用较高的情况. TOP 查看发现大部分占用CPU的都是 JAVA核心进城后附近的进程. 所以初步怀疑 是出现了FullGC的问题. 然后群里反馈了 ...
- Springboot下micrometer+prometheus+grafana进行JVM监控的操作过程
Springboot下micrometer+prometheus+grafana进行JVM监控的操作过程 背景 同事今天提交了一个补丁. 给基于Springboot的产品增加了micrometer等收 ...
- 《Javascript高级程序设计》读书笔记——继承与原型链
继承与原型链 原型链 在原型那一节中,讲到了用于搜索对象属性的原型搜索机制:而原型链,本质上 就是对原型搜索机制的扩充: 回想下之前的内容,我们要读取一个Person的实例p属性,会先搜索实例p:如果 ...
- 软件缺陷(bug)
生活中我们肯定听过身边的朋友说过:'这tm就是个bug','你就是bug一样的存在' 等话语.当你听到这句话的时候或许有些懵逼或许认为这货说的什么玩意.其实当你想成为一名测试工程师的时候你就要天天和b ...
- CCPC Finals 2021 H Harie Programming Contest (网络流&支配树的妙用)
Link 题意: 给一个二分图,求有多少种方案删去恰好两个点,使得最大匹配数不变.\(n,m\le 2\times 10^5\). 二话不说先跑一遍 Dinic 网络流,设残量网络形成的图为 \(G\ ...
- 微信小程序网页嵌入开发
无脑开发 下载微信开发者工具 新建一个项目找到index开头的进去全选删除粘贴下面代码 <!-- html --> <!-- 指向嵌入外部链接的地址 --> <web-v ...
- Vue双向数据绑定原理-上
Vue响应式的原理(数据改变界面就会改变)是什么? 时时监听数据变化, 一旦数据发生变化就更新界面, 这就是Vue响应式的原理. Vue是如何实现时时监听数据变化的 通过原生JS的defineProp ...