JVM虚拟机-运行时数据区概述
运行时数据区域
总览
JDK. 1.7 之后版本略有不同
Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。
有必要深入了解这块的内容,因为它将决定服务器性能,除此之外还有助于快速定位虚拟机的相关Error。
首先来对整个运行时区域有一个整体的认识。
如下图
JDK 1.7 之前:

JDK 1.7 以及之后(1.8正式使用,1.7还需要手动设置一下) :

线程私有的(图中红色)
线程共享的(图中绿色、蓝色)
概念扫盲
什么是栈帧(Stack Frame)
每一次函数的调用,都会在调用栈上维护一个独立的栈帧,每个独立的栈帧一般包括:
- 函数的返回地址和参数
- 临时变量
- 函数调用的上下文
栈是从高地址向低地址延伸,一个函数的栈帧用ebp 和 esp 这两个寄存器来划定范围。
ebp 指向当前的栈帧的底部,esp 始终指向栈帧的顶部。
- ebp 寄存器又被称为帧指针(Frame Pointer)
- esp 寄存器又被称为栈指针(Stack Pointer)
JVM常见出现两种错误
StackOverFlowError: 若 Java 虚拟机栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前 Java 虚拟机栈的最大深度的时候,就抛出StackOverFlowError错误。OutOfMemoryError: Java 虚拟机栈的内存大小可以动态扩展, 如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常异常。
程序计数器
程序计数器占用较小的一块内存空间,每条线程都需要有一个独立的程序计数器,程序计数器用于记录当前线程执行的位置,从而当线程被来回切换的时候,能够知道该线程上次运行到哪儿了。
字节码解释器工作时通过改变这个计数器的值,来选取下一条需要执行的字节码指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
它的生命周期随着线程的创建而创建,随着线程的结束而死亡。
程序计数器是唯一一个不会出现
OutOfMemoryError的内存区域。
虚拟机栈
结构
虚拟机栈也是线程私有,而且生命周期与线程相同。
每个Java方法在执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。

局部变量表
- 存放编译器可知的各种基本数据类型(boolean、byte等)
- 对象引用(reference类型,它不等同于对象本身)
- 可能是一个指向对象起始地址的引用指针
- 也可能是指向另一个代表对象的句柄
- 其他次对象相关的位置
- returnAddress类型,指向了一条字节码指令的地址
方法是如何调用的
每一次函数调用都会有一个对应的栈帧被压入 Java 栈,每一个函数调用结束后,都会有一个栈帧被弹出。
Java 方法有两种返回方式:
- return 语句。
- 抛出异常。
不管哪种返回方式都会导致栈帧被弹出。
本地方法栈
主要为虚拟机使用到的Native方法服务,作用其实类似虚拟机栈,其结构也和虚拟机栈一样
二者的区别是虚拟机栈为虚拟机执行字节码服务。
本地方法被执行的时候,在本地方法栈也会创建一个栈帧,用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。
方法执行完毕后相应的栈帧也会出栈并释放内存空间。
在 HotSpot 虚拟机中和虚拟机栈合二为一
堆
Java 堆是所有线程共享的一块内存区域,在虚拟机启动时创建。
此内存区域的目的是存放对象实例,几乎所有的对象实例以及数组都在这里分配内存。
说是几乎是因为由于多项技术的进步与成熟,如:逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术,一些对象也可能在栈上分配内存。
Java 堆是JVM中最大的一块内存区域,也是是垃圾回收(Garbage Collected)管理的主要区域,故又叫做GC堆。
浅堆和深堆
浅堆和深堆是两个非常重要的概念,理解他们之前需要先了解什么是保留集。
保留集,即为只被单一对象所持有的对象的集合,如图:

- 浅堆是指一个对象所消耗的内存。如上图
- 深堆是指对象的保留集中所有的对象的浅堆大小之和。
堆的细分
HotSpot中还有永久代的概念,不过已经是历史了。
JDK 8 HotSpot 的永久代被彻底移除,取而代之是元空间,元空间使用的是直接内存。
现在垃圾收集器基本都采用分代垃圾收集算法,所以 Java 堆还可以细分,堆分为新生代(占堆1/3),老生代(占堆2/3)
- 新生代(内部比例8:1:1)
- Eden 空间
- From Survivor 空间
- To Survivor 空间
- 老年代
进一步划分的目的是更好地回收内存,或者更快地分配内存。
流程:
- 大多数情况,对象都会首先在 Eden 区域分配
- 在一次新生代垃圾回收后,如果对象还存活,则会进入两个Survivor中的一个,然后对象的年龄加 1
- 它的年龄增加到年龄阈值(默认为 15 ),就会被晋升到老年代中
对象晋升到老年代的年龄阈值,可以通过参数
-XX:MaxTenuringThreshold设置
方法区
方法区与 Java 堆一样,也是所有线程共享的。
主要用于存储类的信息、常量池、方法数据、方法代码等。
方法区逻辑上属于堆的一部分,但是为了与堆进行区分,有一个别名叫做 Non-Heap(非堆)
该区域的内存回收目标主要针对常量池的回收和类型的卸载。
在HotSpot虚拟机中,用永久代来实现方法区,但是这样容易遇到内存溢出的问题,所以在Java 8之后就取消了方法区。
方法区和永久代的关系
摘自《深入理解Java虚拟机》第三版
《Java 虚拟机规范》只是规定了有方法区这么个概念和它的作用,并没有规定如何去实现它。那么,在不同的 JVM 上方法区的实现肯定是不同的了。 方法区和永久代的关系很像 Java 中接口和类的关系,类实现了接口,而永久代就是 HotSpot 虚拟机对虚拟机规范中方法区的一种实现方式。 也就是说,永久代是 HotSpot 的概念,方法区是 Java 虚拟机规范中的定义,是一种规范,而永久代是一种实现,一个是标准一个是实现,其他的虚拟机实现并没有永久代这一说法。
为什么要将永久代替换为元空间 ?
- 永久代内存有一个JVM固定的上限,经常会出现
OutOfMemoryError。 - 元空间使用的是直接内存,受本机可用内存的限制,虽然元空间仍旧可能溢出,但是比原来出现的几率会更小。
- 元空间里面存放的是类的元数据,由系统的实际可用空间来控制,这样能加载的类就变多了。
- 在 JDK8,合并 HotSpot 和 JRockit 的代码时,JRockit 没有永久代,如果强行保留实现起来困难重重。
当元空间溢出时会得到如下错误:
java.lang.OutOfMemoryError: MetaSpace
运行时常量池
运行时常量池用于存放编译期间生成的各种字面量和符号引用,是方法区的一部分。
运行时常量池用来动态获取类信息,包括:
- Class文件元信息描述
- 编译后的代码数据
- 引用类型数据
- 类文件常量池
运行时常量池是在类加载完成之后,将每个Class常量池中的符号引用值转存到运行时常量池中。
每个Class都有一个运行时常量池,类在解析之后将符号引用替换成直接引用,与全局常量池中的引用值保持一致。
运行时常量池相的另外一个重要特性是具备动态性,Java语言并不要求常量一定只有编译器才能产生,也就是并非预置入Class文件中的常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中。
直接内存
直接内存并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用。
使用的方式是通过 JDK1.4 中加入的NIO(New Input/Output)类,它可以直接使用 Native 函数库直接分配堆外内存。
通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。
避免了在 Java 堆和 Native 堆之间来回复制数据,在一些场景中显著提高了性能,
本机直接内存的分配不受 Java 堆的限制,但受到本机总内存大小,以及处理器寻址空间的限制,因此也可能导致 OutOfMemoryError 错误出现。
总结
以上的各个分区,各司其职,是了解Java虚拟机的基础。
理解各区域的指责和作用,对JVM后续的学习有非常大的帮助,如果这些没搞懂,后面学起来是真头大。
结合图例,相信可以较为清晰了理解各分区的架构和指责,觉得有用欢迎点个推荐、点个赞。
参考:
《深入理解Java虚拟机》第三版 ——周志明 (吹爆)
JVM虚拟机-运行时数据区概述的更多相关文章
- 【JVM之内存与垃圾回收篇】运行时数据区概述及线程
运行时数据区概述及线程 前言 本节主要讲的是运行时数据区,也就是下图这部分,它是在类加载完成后的阶段 当我们通过前面的:类的加载-> 验证 -> 准备 -> 解析 -> 初始化 ...
- 【JVM从小白学成大佬】2.Java虚拟机运行时数据区
目录 1.运行时数据区介绍 2.堆(Heap) 是否可能有两个对象共用一段内存的事故? 3.方法区(Method Area) 4.程序计数器(Program Counter Register) 5.虚 ...
- 【JVM学习】2.Java虚拟机运行时数据区
来源: 公众号: 猿人谷 这里我们先说句题外话,相信大家在面试中经常被问到介绍Java内存模型,我在面试别人时也会经常问这个问题.但是,往往都会令我比较尴尬,我还话音未落,面试者就会"背诵& ...
- 面试常问的 Java 虚拟机运行时数据区
写在前面 本文描述的有关于 JVM 的运行时数据区是基于 HotSpot 虚拟机. 概述 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以 ...
- Java 虚拟机运行时数据区
写在前面 本文描述的有关于 JVM 的运行时数据区是基于 HotSpot 虚拟机. 概述 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以 ...
- Java 虚拟机运行时数据区详解
本文摘自深入理解 Java 虚拟机第三版 概述 Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟 ...
- JVM入门——运行时数据区
这张图我相信基本上对JVM有点接触的都应该很熟悉,可以说这是JVM入门的第一课.其中的“堆”和“虚拟机栈(栈)”更是耳熟能详.下面将围绕这张图对JVM的运行时数据区做一个简单介绍. 程序计数器(Pro ...
- jvm理论-运行时数据区
三大流行jvm sun HotSpot ibm j9 BEA JRockit Oracle 会基于HotSpot整合 JRockit. jvm运行时数据区 java虚拟机所管理的内存将会包括以下几个运 ...
- 《深入理解Java虚拟机》(二)Java虚拟机运行时数据区
Java虚拟机运行时数据区 详解 2.1 概述 本文参考的是周志明的 <深入理解Java虚拟机>第二章 ,为了整理思路,简单记录一下,方便后期查阅. 2.2 运行时数据区域 Java虚拟机 ...
随机推荐
- 【海思】Hi3516A 运行sample_venc的demo内核奔溃(DDR问题)
作者:李春港 出处:https://www.cnblogs.com/lcgbk/p/14514297.html 目录 一.前言 二.使用memtester对ddr进行压力测试 三.修改uboot的DD ...
- SQL练习——LeetCode解题和总结(1)
只用于个人的学习和总结. 178. Rank Scores 一.表信息 二.题目信息 对上表中的成绩由高到低排序,并列出排名.当两个人获得相同分数时,取并列名次,且名词中无断档. Write a SQ ...
- Elasticsearch 复合查询——多字符串多字段查询
前言 有时我们在搜索电影的时候,包含了多个条件,比如主演是周星驰,打分8分以上,上映时间是1990年~2001年的,那么Elasticsearch又该如何帮我们做查询呢?这里我们可以用 bool 查询 ...
- exe取消动态基址
动态基址开启后,在动态调试是想要和ida静态分析中的地址对应还要进行一步计算,取消动态基址便可以剩下很多时间. 只要修改pe文件头中的Characteristics低位置1 1 typedef str ...
- 运维小姐姐说这篇Consul集群和ACL配置超给力(保姆级)
前言 上一篇简单介绍了Consul,并使用开发模式(dev)进行流程演示,但在实际开发中需要考虑Consul的高可用和操作安全性,所以接着来聊聊集群和ACL的相关配置,涉及到的命令会在环境搭建过程中详 ...
- 【Azure 应用服务】App Service 在使用GIt本地部署,上传代码的路径为/home/site/repository,而不是站点的根目录/home/site/wwwroot。 这个是因为什么?
问题描述 App Service 在使用GIt本地部署,上传代码的路径为/home/site/repository,而不是站点的根目录/home/site/wwwroot. 这个是因为什么? 并且通过 ...
- ES核心概念和原理
ES:1:倒排索引 基于Document 关键词索引实现 . 根据关键词做索引 相关度 a. 数据结构 i. 包含关键词的Document List ii. 关键词在每个doc中出现的次数 词频 TF ...
- OpenCV图像处理中“投影技术”的使用
本文区分"问题引出"."概念抽象"."算法实现"三个部分由表及里具体讲解OpenCV图像处理中"投影技术" ...
- java例题_18 乒乓球比赛(对手问题)
1 /*18 [程序 18 乒乓球赛] 2 题目:两个乒乓球队进行比赛,各出三人.甲队为 a,b,c 三人,乙队为 x,y,z 三人.已抽签决定比赛名单. 3 有人向队员打听比赛的名单.a说他不和 x ...
- (数据科学学习手札115)Python+Dash快速web应用开发——交互表格篇(上)
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...