JVM 运行时数据区:程序计数器、Java 虚拟机栈和本地方法栈,方法区、堆以及直接内存
Java 虚拟机可以看作一台抽象的计算机,如同真实的计算机,它也有自己的指令集和运行时内存区域。
Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存(运行时内存区域)划分为若干个不同的数据区域。
如下图所示:

一、程序计数器 Program Counter Register
1.定义:程序计数器是当前线程所执行字节码的行号指示器。
2.线程私有内存的原因:Java 中的多线程是线程间轮流切换并需要 CPU 给予时间片的方式实现的。在任何一个确定的时刻,都只有一个线程在执行指令。为了线程间轮流切换后能够快速恢复到正确执行的位置,每一个线程都有自己的程序计数器,各线程间程序计数器互不影响,独立存在。因此,程序计数器是 “线程私有” 的内存区域。
3.详解:在当前线程执行 Java 指令时,程序计数器中存储的是正在执行的字节码的地址;而当前线程执行 native 方法时,程序计数器存储值为空。
字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程回复等基础功能都需要依赖这个计数器来完成。
4.可能导致的错误:程序计数器是 Java 运行时内存区域中唯一一个不会抛出 OutOfMemoryError (OOM)情况的内存区域。
二、Java 虚拟机栈 JVM Stacks
1.定义:Java 虚拟机栈描述的是 Java 方法执行的内存模型。
2.线程私有内存的原因:在当前线程执行方法时,Java 虚拟机栈会创建一个对应该方法的栈帧(Stack Frame)。栈帧中有 局部变量表、操作数栈、动态链接和方法出口等信息。
每一个方法从调用到执行完成时,都对应着栈帧从入栈到出栈的过程。
3.详解:局部变量表存放了各种编译器可知的基本数据类型、对象引用类型和 returnAddress 类型。局部变量表大小在编译期就已确定了,当进入一个方法时,栈帧需要分配给局部变量表的内存空间早已固定,不会再做更改。
(关于 JVM Stacks 的详细情况可能放在 本系列 JVM 执行引擎 一文 中)
4.可能抛出的错误:
1.当请求的栈深度超越规定的栈深度时,便会抛出 StackOverflowError (sof) 异常
2.虚拟机栈动态扩展时,如果无法申请到足够的内存,抛出 OOM 异常
三、本地方法栈
1. 定义:本地方法栈描述的是运行时 native 方法的内存模型。
2.解释:本地方法栈与 Java 虚拟机栈几乎相同,只不过本地方法栈对应的是本地方法,Java 虚拟机栈对应的是 Java 方法。
Hotspot 虚拟机将 java 虚拟机栈与本地方法栈合二为一。
3.可能抛出的异常同 Java 虚拟机栈一样(SOF,OOM)
本地方法的解释:Java 本地方法
四、Java 堆
1. 定义:Java 堆是一块用来存放对象实例的运行时内存空间。
2.Java 堆唯一目的就是用来存放对象实例。几乎所有的对象实例(包括数组)都会在这里分配内存。属于“线程共享"的内存区域。
Java 堆是垃圾回收器管理的主要区域。Java 虚拟机可以处于物理上的不连续内存空间中,只要逻辑上是连续的内存空间即可。
java 堆是垃圾回收的主要区域
3.可能抛出的异常:
如果堆中没有内存完成实例分配,并且堆再也无法扩展时,那么会抛出 OOM 异常
五、方法区
1.定义:方法区用于存储已被虚拟机加载的类的结构信息、常量、静态变量、即时编译器编译后的静态代码等数据。
方法区是线程共享的内存区域。
2.解释:在 Hotspot 虚拟机上,方法区采用永久代的方式实现,因此方法区又被称为永久代(Permanent Generation),实际上这两者并不等价。因为这样实现的方法区不仅容易遇到内存溢出的问题,而且极少数方法(String.intern) 也会在不同的虚拟机上有不同的表现。
Hotspot 虚拟机现在也有放弃永久代而采用 Native Memory 来实现方法区的规划了(在 JDK1.7 中,将放在永久代的字符串常量池移出)。
对于垃圾回收而言,方法区主要集中在常量池的回收和类类型的卸载这两方面。但是方法区的垃圾回收效果可谓是差强人意,特别是类类型的卸载,不过这部分类型的回收又是必须的。
3. 可能抛出的异常:
方法区如果无法满足内存分配需求时,将会抛出 OOM 异常。
5.1 方法区重要组成部分: 运行时常量池 Runtime Constant Pool
1.定义:运行时常量池是 class 文件中每一个类或接口的常量池表的运行时表现形式,包括若干种不同的常量,从编译期可知的数值字面量到必须在运行期解析后才能获得的方法和字段引用。
每一个运行时常量池都在 Java 虚拟机的方法区中分配,在加载类和接口到虚拟机后,就将相应的常量放入运行时常量池。
2.可能抛出的异常:
当常量池无法再申请到内存时会抛出 OOM 异常
3.例子:
public class A {
public static void main(String[] args) {
String a = "abc";
String b = "abc";
System.out.println(a==b);
String c = new String("abc");
System.out.println(a==c);
System.out.println(a==c.intern());
}
}
六、直接内存 Direct Memory
在 JDK1.4 中新加入了 NIO(New Input/Output) 类,引入了一种基于通道(Channel) 与缓冲区(Buffer) 的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆中来回复制数据。
显然,本机直接内存的分配不会受到 Java 堆大小的限制,但是,既然是内存,坑定还是受到本机总内存(包括 RAM 以及 SWAP 区或者分页文件)大小以及处理器寻址空间的限制。服务器管理员在配置虚拟机参数时,会根据实际内存设置 -Xmx 等参数信息,但经常忽略直接内存,使得各个内存区域总和大于物理内存限制(包括物理的和操作系统级的限制),从而导致动态扩展时出现 OOM 的异常。
JVM 运行时数据区:程序计数器、Java 虚拟机栈和本地方法栈,方法区、堆以及直接内存的更多相关文章
- JDK1.8-Java虚拟机运行时数据区域和HotSpot虚拟机的内存模型
目录 介绍 官方文档规定的运行时数据区域 程序计数器 Java虚拟机栈 本地方法栈 虚拟机栈和本地方法栈溢出 Java堆 演示堆内存溢出 方法区 运行时常量池 演示方法区溢出 HotSpot虚拟机的内 ...
- Jvm运行时数据区 —— Java虚拟机结构小记
关于jvm虚拟机的文章网上都讲烂了.尤其是jvm运行时数据区的内容. 抱着眼见为实的想法,自己翻了翻JVM规范,花了点时间稍微梳理了一下. 以下是阅读Java虚拟机规范(Java SE 8版)的第二章 ...
- Java内存管理:Java内存区域 JVM运行时数据区
转自:https://blog.csdn.net/tjiyu/article/details/53915869 下面我们详细了解Java内存区域:先说明JVM规范定义的JVM运行时分配的数据区有哪些, ...
- 深入理解Java虚拟机 -- 读书笔记(1):JVM运行时数据区域
深入理解Java虚拟机 -- 读书笔记:JVM运行时数据区域 本文转载:http://blog.csdn.net/jubincn/article/details/8607790 本系列为<深入理 ...
- Java中的字符串常量池和JVM运行时数据区的相关概念
什么是字符串常量池 JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池 工作原理 当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量 ...
- Jvm运行时数据区
一:运行时数据区 Java虚拟机在执行Java程序的过程中会把它管理的内存分为若干个不同的数据区域.这些区域有着各自的用途,一级创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户 ...
- JVM运行时数据区内容简述
JVM运行时数据区分为五个部分:程序计数器.虚拟机栈.本地方法栈.堆.方法区.如下图所示,五部分其中又分为线程共享区域和线程私有区域,下面将分别介绍每一部分. 1. PC程序计数器 程序计数器是一块较 ...
- JVM 运行时数据区 (三)
JVM运行时数据区 运行时数据区由 程序计数器.java虚拟机栈.本地方法栈.堆.方法区 组成: 1.程序计数器 每一个Java线程都有一个程序计数器,用于保存程序执行到当前方法的哪一个指令,它是线程 ...
- JVM总结(一):概述--JVM运行时数据区
大三下,趁着寒假重温一遍JVM,准备在一个系列来总价一下学习JVM的整个过程.争取在接下来的一个星期内更新完这一个系列,然后回家过年. JVM运行时数据区 线程私有的数据区 程序计数器 虚拟机栈 本地 ...
- JVM运行时数据区和垃圾回收机制
最近参考各种资料,尤其是<深入理解Java虚拟机 JVM高级特性和最佳实践>,大牛之作.把最近学习的Java虚拟机组成和垃圾回收机制总结一下. 你不会的都是新知识,学无止境,每天进步一点点 ...
随机推荐
- ABP 往前端返回详细的错误信息
在这个类:MyABP.Web.Startup.MyABPWebMvcModule 中 的 PreInitialize 方法 添加一句: Configuration.Modules.AbpWebComm ...
- 洛谷p1559运动员最佳匹配问题
题目 搜索 可行性剪枝 虽然这题目是我搜二分图的标签搜到的 但是n比较小 明显可以暴力 然而只有80分 再加上可行性剪纸就行啦 就是记所有运动员他所能匹配到的最大值. 在我们搜索到第i层的时候 如果他 ...
- NDCG、AUC介绍
https://blog.csdn.net/u014313009/article/details/38944687 SIGIR的一篇推荐算法论文中提到用NDCG和AUC作为比较效果的指标,之前没了解过 ...
- springboot项目打包成jar/war包
springboot项目打包过程中包含第三方jar 开发IDE是IntelliJ IDEA,数据库是mysql,内置服务器tomcat. 打包步骤: 1. 确定项目调试运行没问题 2. 将第三方jar ...
- ASP.NET Core Windows服务开发技术实战演练
一.课程介绍 人生苦短,我用.NET Core!大家都知道如果想要程序一直运行在Windows服务器上,最好是把程序写成Windows服务程序:这样程序会随着系统的自动启动而启动,自动关闭而关闭,不需 ...
- docker 学习操作记录 5-2
记录5-2 root@53d0a643a2c7:/# quit bash: quit: command not found root@53d0a643a2c7:/# exit exit -->@ ...
- SQLite中字段顺序和PAGE_SIZE对性能的影响
1.背景 SQLite数据库中有1张表,该表含若干个字段,其中有1个字段为BLOB类型,且BLOB字段不是最后1个字段.表结构类似如下(col3为BLOB字段): T (col1 INTEGER,co ...
- ps 简单使用 ----- 将图片静态图片制作成动图
1. 准备好你需要静态图片 放到文件夹中 2.打开ps 软件 将右上角切换为 动感 3.观察下方时间轴 点击加号 将图片导入 按住shift 选择图片 4.切换为帧格式 选择循环 ...
- [转帖]centos7 使用kubeadm 快速部署 kubernetes 国内源
centos7 使用kubeadm 快速部署 kubernetes 国内源 https://www.cnblogs.com/qingfeng2010/p/10540832.html 前言 搭建kube ...
- 【题解】Luogu P4284 [SHOI2014]概率充电器
原题传送门 我们知道,每个电器充电对充电电器数的贡献都是相等的1,所以若第\(i\)个电器有\(p_i\)的概率充电时 \[E=\sum_{i=1}^np_i\] 我们考虑如何求\(p_i\),根据树 ...