深入理解JVM虚拟机读书笔记——运行时数据区
注:本文参考自周志明老师的著作《深入理解Java虚拟机(第3版)》,相关电子书可以关注WX公众号,回复 001 获取。
跨平台性是 Java 语言的重要特性,而这一特性本质上就是通过 JVM 虚拟机来实现的。下面就来通过深入学习 JVM 来进一步增加我们对 Java 这门编程语言的了解吧!(个人建议,最好能买来这本书去读一读,是非常有帮助的,当然,在看这本书之前,为了方便理解相关概念名词,可以先跟着某马程序员的视频课程大致过一遍 JVM 的内容体系:JVM 虚拟机基础入门视频教程,视频教程的全套笔记)
1. 运行时数据区
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里 面的人却想出来 —— 摘自(深入理解 Java 虚拟)。
Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域 有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而一直存在,有些区域则是依赖用户线程的启动和结束而建立和销毁。根据《Java虚拟机规范》的规定,Java虚拟机所管理的内存 将会包括以下几个运行时数据区域,如下图所示。
下面我们来逐个学习一下运行时数据区的 5 个部分。(注意:JVM 运行时数据区可不能等同于 JVM 内存模型,对于不太熟悉 JVM 的初学者,面试的时候很容易把这两个概念搞混~)
1.1 程序计数器
程序计数器(线程私有),是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。它的核心作用就是:用于存储下一条所要执行的 JVM 指令的内存地址。
这里所说的线程私有,即不会出现并发安全问题,JVM 运行时数据区的 5 个部分中,只有 Java 堆、方法区是线程共享的,其他三个均为线程私有,后面还会提到这个知识点。
如下图:
Java指令执行流程:
- 每一条二进制字节码(JVM指令) 通过 解释器 转换成 机器码 然后 就可以被 CPU 执行了!
- 当 解释器 将一条jvm 指令转换成 机器码后 其会 向程序计数器 递交 下一条 jvm 指令的执行地址!
- 程序计数器在硬件层面 其实是通过 寄存器 实现的!
- 所以程序计数器的作用就是:用于保存JVM中下一条所要执行的指令的地址!
1.2 虚拟机栈
与程序计数器一样,虚拟机栈也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是J ava 方法执行的线程内存模型:每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧(Stack Frame),栈帧包含如下几个组成部分:
- 局部变量表:存放基本数据类型(
boolean、byte、char、short、int、 float、long、double
)、对象引用(reference)等。这些数据类型在局部变量表中的存储空间以局部变量槽(Slot)来表示,其中64位长度的long
和double
类型的数据会占用两个变量槽,其余的数据类型只占用一个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小(这里说的“大小”是指变量槽的数量)。 - 操作数栈:也可以称之为表达式栈(Expression Stack),在方法执行过程中,根据字节码指令,往栈中写入数据或提取数据,即入栈(push)和 出栈(pop)。某些字节码指令将值压入操作数栈,其余的字节码指令将操作数取出栈,使用它们后再把结果压入栈,比如:执行复制、交换、求和等操作。操作数栈,主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间。
- 动态连接
- 方法出口等信息
每个线程运行需要的内存空间,这一空间被称为虚拟机栈(Frames),每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
每个栈由多个栈帧(Frame) 组成,对应着每个方法运行时所占用的内存,每个线程只能有一个活动栈帧,对应着当前正在执行的方法,当方法执行时压入栈,方法执行完毕后弹出栈。
如下图:
1.3 本地方法栈
一些带有native 关键字的方法就是需要JAVA去调用本地的C或者C++方法,因为JAVA有时候没法直接和操作系统底层交互,所以需要用到本地方法!
如图:
1.4 堆
堆是Java内存区域中一块用来存放对象实例的区域【几乎所有的对象实例都在这里分配内存】,Java 堆(Java Heap)是 Java 虚拟机所管理的内存中最大的一块 Java 堆是被所有线程共享的一块内存区域。
Java堆既可以被实现成固定大小的,也可以是可扩展的,不过当前主流的Java虚拟机都是按照可扩展来实现的(通过参数-Xmx
和-Xms
设定)。如果在Java堆中没有内存完成实例分配,并且堆也无法再扩展时,Java虚拟机将会抛出OutOfMemoryError
异常。
- 内存中的对象都需要考虑线程安全问题。
- Java 堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC 堆”(Garbage)。
-Xmx -Xms:
JVM初始分配的堆内存由-Xms
指定,64位的操作系统上,堆大小默认是物理内存的1/64
。
1.5 方法区
方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
方法区只是一个抽象概念,其具体实现是通过以下 2 种方式:
- 永久代:JDK1.7版本之前。
- 元空间:JDK1.8版本之后。
永久代如下图所示:
元空间如下图所示:
由上图可以看出,1.6版本方法区是由PermGen永久代实现(使用堆内存的一部分作为方法区),且由JVM 管理,由Class ClassLoader 常量池(包括StringTable) 组成。
1.8 版本后,方法区交给本地内存管理,而脱离了JVM,由元空间实现(元空间不再使用堆的内存,而是使用本地内存,即操作系统的内存),由Class ClassLoader 常量池(StringTable 被移到了Heap 堆中管理) 组成。
2. 面试题案例
- JVM面试题案例
后续会陆续更新,这本书的笔记记的差不多了,排版和格式需要花时间整理,文章都会同步到公众号上,也欢迎大家通过公众号加入我的交流qun互相讨论jvm这块的知识内容!
深入理解JVM虚拟机读书笔记——运行时数据区相关推荐
- Java 虚拟机学习笔记 | 运行时数据区总结
前言 要想学习好 Java,Java虚拟(JVM)的学习是绕不开的.学习 Java虚拟(JVM)首先就要先了解的就是Java虚拟(JVM)运行时数据区. 在Java语言和虚拟机规范中对运行时数据区进行 ...
- 深入理解JVM虚拟机读书笔记——内存模型与线程
注:本文参考自周志明老师的著作<深入理解Java虚拟机(第3版)>,相关电子书可以关注WX公众号,回复 001 获取. 1. Java内存模型 JMM概述: Java 内存模型指的是 JM ...
- JVM(类加载、运行时数据区、堆内存、方法区、本地接口、执行引擎和垃圾回收)java虚拟机(JVM)的超详细知识点
JVM虚拟机 一.JVM的概述 1.为什么要学习JVM 2.虚拟机 3.JVM的作用 作用 特点 4.JVM的位置 5.JVM的分类 6.各个组成部分的用途 7.Java 代码的执行流程 8.JVM ...
- Java #JVM(HotSpot) 运行时数据区 #程序计数器(PC寄存器)#虚拟机栈(栈帧:局部变量表、操作数栈……)#堆……
目录 JVM中线程的说明 程序计数器(PC寄存器) 虚拟机栈 · 栈帧 ·· 局部变量表 ·· 操作数栈 ·· 动态链接 ·· 方法返回地址 ·· 本地方法栈 堆 · 查看堆的大小 · 堆的默认大小 ...
- JVM内存区域(运行时数据区)划分
前言: 我们每天都在编写Java代码,编译,执行.很多人已经知道Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文 ...
- 深入理解JVM虚拟机读书笔记——锁优化
注:本文参考自周志明老师的著作<深入理解Java虚拟机(第3版)>,相关电子书可以关注WX公众号:兴趣使然的草帽路飞,回复 001 获取. 1. Java语言中的线程安全 按照线程安全的& ...
- 深入理解JVM虚拟机读书笔记【第十二章】Java内存模型与线程
12.1 概述 12.2 硬件的效率与一致性 12.3 Java内存模型 12.3.1 主内存与工作内存 12.3.2 内存间交互操作 12.3.3 对于volatile型变量的特殊规则 12.3.4 ...
- JVM学习笔记之-运行时数据区概述及线程概述,程序计数器(PC寄存器),虚拟机栈(栈,局部变量表,操作数栈,动态连接,方法调用,方法返回地址等),本地方法接口,本地方法栈
运行时数据区概述及线程概述 内存是非常重要的系统资源,是硬盘和CPU的中间仓库及桥梁,承载着操作系统和应用程序的实时运行.JVM内存布局规定了Java在运行过程中内存申请.分配.管理的策略,保证了JV ...
- 【JVM】运行时数据区介绍,程序计数器和虚拟机栈详解
JVM越来越是Java面试中的重头戏,今天来总结一下JVM运行时数据区的相关内容. 文章目录 JVM运行时数据区 JVM运行时数据区内部结构 程序计数器(PC寄存器) 程序计数器的介绍 PC寄存器的实 ...
- 【JVM】运行时数据区概述(程序计数器、虚拟机栈、本地方法栈)
前言 本节主要讲的是运行时数据区,也就是下图这部分,它是在类加载完成后的阶段 当我们通过前面的:类的加载-> 验证 -> 准备 -> 解析 -> 初始化 这几个阶段完成后,就会 ...
最新文章
- Entity Framework Core延期及弃用的特性
- 【搜索/推荐排序】NCF,DeepCross,Deep Crossing
- 常用API2 正则表达式
- 反编译工具Reflector ILSpy
- 编写一份代码,支持多种布署方式
- Google 杀死了 160 个产品!
- 练习--第一次课(运算if while 字符编码)
- 关于verilog的一些基础知识整理
- Yii 2.0 权威指南(7) 关键概念
- mysql表格字放大_删除MySQL表中内容,表大小反而变大了
- cisco 3750G 冗余备份
- CentOS安装NTFS-3G读写Windows 10的移动NTFS磁盘
- 网易音乐网站系统|前后端分离springboot+vue实现在线音乐网站
- Git 学习笔记:6 GitHub
- 速看!!带你揭秘3D建模行业内幕!!
- git remote add origin xxx.git 的问题解决
- 电影《可可西里》散记
- 从匿名聊聊被封停,看微信小程序坚持的线下策略
- Pyecharts 静态图片输出ppt中动态图表
- 晶振频率,时钟频率,时钟周期,时钟节拍,机器周期,指令周期的概念解析