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虚拟机组成和垃圾回收机制总结一下. 你不会的都是新知识,学无止境,每天进步一点点 ...
随机推荐
- [RN] React Native代码转换成微信小程序代码的转换引擎工具
React Native代码转换成微信小程序代码的转换引擎工具 https://github.com/areslabs/alita
- MYSQL:基于哈希的索引和基于树的索引有什么区别?
B+树是一个平衡的多叉树.B+树从根节点到叶子节点的搜索效率基本相当,不会出现大幅波动. 哈希索引采用一定的哈希算法,把键值换成新的哈希值,检索时不需要类似B+树那样从根节点逐级查找,只需一次哈希算法 ...
- map函数怎么用咧↓↓↓
Map是c++的一个标准容器,她提供了很好一对一的关系,在一些程序中建立一个map可以起到事半功倍的效果,总结了一些map基本简单实用的操作! 1. map最基本的构造函数: map<st ...
- 关于.ipynb文件
一.简介: .ipynb文件即为Jupyter Notebook,是一个交互式笔记本,支持运行 40 多种编程语言. Jupyter Notebook 的本质是一个 Web 应用程序,便于创建和共享文 ...
- 石锤了!google彻底断供华为,只能加速鸿蒙生态的形成
前言 操作系统是当今科技行业的灵魂,而即将推出这款操作系统是一个集电脑.手机.汽车等设备于一体的系统.如今手机行业里已经是一片红海了,竞争相当激烈,但是竞争归竞争,但是一旦扯上别的事就更麻烦了,像华为 ...
- 【Java】15分钟快速体验阿里Java诊断工具Arthas
[墙裂推荐]15分钟快速体验阿里Java诊断工具Arthas : https://alibaba.github.io/arthas/arthas-tutorials?language=cn&i ...
- 【原创】在windows下使用xampp搭建phpcms v9
我的操作环境: 操作系统:windows 7 64 位操作系统(有点古老,哈哈) 1.下载php环境和phpcmsv9源代码:phpcms v9 的源码:phpcms_v9.5.10_UT ...
- shell三剑客之sed
背景 sed(Stream Editor 流编辑器),作为三剑客的一份子,主要的功能有增删改查.为什么称之为"流"编辑器呢?大家知道:在Linux文件系统中,一切都可以作为文件来处 ...
- Android实时打印内核log
由于访问的是/proc/kmsg,因此需要先获取root权限: adb root adb shell "while true; do cat; sleep 1; done < /pro ...
- 【剑指offer】构建乘积数组
题目描述 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1].不 ...