一、运行时数据区域

1.程序计数器

  程序计数器( Program Counter Register) 是一块较小的内存空间, 它可以看作是当前线程所执行的字节码的行号指示器。 Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻, 一个处理器( 对于多核处理器来说是一个内核) 都只会执行一条线程中的指令。 因此, 为了线程切换后能恢复到正确的执行位置, 每条线程都需要有一个独立的程序计数器, 各条线程之间计数器互不影响, 独立存储, 我们称这类内存区域为“线程私有”的内存。如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址; 如果正在执行的是Native方法, 这个计数器值则为空( Undefined) 。 此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

2.Java虚拟机栈

  与程序计数器一样,Java虚拟机栈也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
  局部变量表存放了编译期可知的各种基本数据类型( boolean、 byte、 char、 short、 int、float、 long、 double) 、 对象引用( reference类型, 它不等同于对象本身, 可能是一个指向对象起始地址的引用指针, 也可能是指向一个代表对象的句柄或其他与此对象相关的位置)和returnAddress类型( 指向了一条字节码指令的地址)。
  在Java虚拟机规范中, 对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度, 将抛出StackOverflowError异常; 如果虚拟机栈可以动态扩展( 当前大部分的Java虚拟机都可动态扩展, 只不过Java虚拟机规范中也允许固定长度的虚拟机栈),如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。

3.本地方法栈

  本地方法栈( Native Method Stack)与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。 在虚拟机规范中对本地方法栈中方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机(譬如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。 与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

4.Java堆

  Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在Java虚拟机规范中的描述是: 所有的对象实例以及数组都要在堆上分配,但是随着JIT编译器的发展与逃逸分析技术逐渐成熟栈上分配、 标量替换优化技术将会导致一些微妙的变化发生, 所有的对象都分配在堆上也渐渐变得不是那么“绝对”了。
  Java堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC堆”。 从内存回收的角度来看, 由于现在收集器基本都采用分代收集算法, 所以Java堆中还可以细分为: 新生代和老年代;再细致一点的有Eden空间、 From Survivor空间、 To Survivor空间等。 从内存分配的角度来看, 线程共享的Java堆中可能划分出多个线程私有的分配缓冲区( Thread Local Allocation Buffer,TLAB)。不过无论如何划分, 都与存放内容无关, 无论哪个区域, 存储的都仍然是对象实例, 进一步划分的目的是为了更好地回收内存, 或者更快地分配内存。
  根据Java虚拟机规范的规定, Java堆可以处于物理上不连续的内存空间中, 只要逻辑上是连续的即可, 就像我们的磁盘空间一样。 在实现时, 既可以实现成固定大小的, 也可以是可扩展的, 不过当前主流的虚拟机都是按照可扩展来实现的( 通过-Xmx和-Xms控制) 。 如果在堆中没有内存完成实例分配, 并且堆也无法再扩展时, 将会抛出OutOfMemoryError异常。

5.方法区

  方法区( Method Area) 与Java堆一样, 是各个线程共享的内存区域, 它用于存储已被虚拟机加载的类信息、 常量、 静态变量、 即时编译器编译后的代码等数据。 虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分, 但是它却有一个别名叫做Non-Heap( 非堆) , 目的应该是与Java堆区分开来。

6.运行时常量池

  运行时常量池(Runtime Constant Pool)是方法区的一部分。 Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池( Constant Pool Table),用于存放编译期生成的各种字面量和符号引用, 这部分内容将在类加载后进入方法区的运行时常量池中存放。
  运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性, Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池, 运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法。

  字面量可以理解为实际值,int a = 8中的8和String a = "hello"中的hello都是字面量

  符号引用就是一个字符串,只要我们在代码中引用了一个非字面量的东西,不管它是变量还是常量,它都只是由一个字符串定义的符号,这个字符串存在常量池里,类加载的时候第一次加载到这个符号时,就会将这个符号引用(字符串)解析成直接引用(指针)

7.直接内存

  直接内存( Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现。在JDK 1.4中新加入了NIO( New Input/Output) 类,引入了一种基于通道( Channel)与缓冲区( Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存, 然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。显然, 本机直接内存的分配不会受到Java堆大小的限制, 但是,既然是内存,肯定还是会受到本机总内存( 包括RAM以及SWAP区或者分页文件)大小以及处理器寻址空间的限制。 服务器管理员在配置虚拟机参数时, 会根据实际内存设置-Xmx等参数信息, 但经常忽略直接内存,使得各个内存区域总和大于物理内存限制( 包括物理的和操作系统级的限制),从而导致动态扩展时出现OutOfMemoryError异常。

深入理解Java虚拟机-JVM运行时数据区域的更多相关文章

  1. 深入理解Java虚拟机(一) 运行时数据区划分

    前言:从我学Java的第一天开始,我的大学老师就告诉我 Java语言相比C.C++的语言有一个非常强大的功能,那就是自动内存管理:我们用Java编码时不需要申请或释放内存等,这些工作全部交由我们的Ja ...

  2. 深入理解Java虚拟机 -- 读书笔记(1):JVM运行时数据区域

    深入理解Java虚拟机 -- 读书笔记:JVM运行时数据区域 本文转载:http://blog.csdn.net/jubincn/article/details/8607790 本系列为<深入理 ...

  3. JVM运行时数据区域

    上面已经聊过JVM是什么东东,也谈过了JVM内存的垃圾回收机制.这一篇博客我们来聊聊JVM运行时数据区域. JVM运行时数据区域由5块部分组成,分别是堆,方法区,栈,本地方法栈,以及程序计数器组成. ...

  4. JVM 运行时数据区域划分

    目录 前言 什么是JVM JRE/JDK/JVM是什么关系 JVM执行程序的过程 JVM的生命周期 JVM垃圾回收 JVM的内存区域划分 一.运行时数据区包括哪几部分? 二.运行时数据区的每部分到底存 ...

  5. Java虚拟机及运行时数据区

    1.Java虚拟机的定义 Java虚拟机(Java Virtual Machine),简称JVM.当我们说起Java虚拟机时,可能指的是如下三种不同的东西: 抽象的虚拟机规范 规范的具体实现 一个运行 ...

  6. Java虚拟机_运行时数据区

    Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域. 这些区域都有各自的用途.各自的创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程启动 ...

  7. 【Java虚拟机】运行时数据区

    Java在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途.创建和销毁的时间,有一些是随虚拟机的启动而创建,随虚拟机的退出而销毁,有些则是与线程一一对应,随 ...

  8. JVM运行时数据区域详解

    参考文章: <Java Se11 虚拟机规范> <深入理解Java虚拟机-JVM高级特性与最佳实践 第3版>- 周志明 本文基于Java Se 11讲解. 根据<Java ...

  9. [jvm]运行时数据区域详解

    了解虚拟机是怎么使用内存的,有助于我们解决和排查内存泄漏和溢出方面的问题.详解java虚拟机内存的各个区域,分析这些区域的作用服务对象以及可能发生的问题. 一.运行时数据区域 java虚拟机在执行ja ...

随机推荐

  1. java POI 导出到word文档 (附工具类)

    1,导入poi相关依赖 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-o ...

  2. Java 使用jcifs读写共享文件夹报错jcifs.smb.SmbException: Failed to connect: 0.0.0.0<00>/10.1.*.*

    Q:使用jcifs读写Windows 10 共享文件夹中的文件报jcifs.smb.SmbException: Failed to connect: 0.0.0.0<00>/10.1.*. ...

  3. python对文件夹内文件去重

    昨天无聊写了一个百度图片爬虫,测试了一下搜索"斗图".一下给我下了3000多个图片,关键是有一半以上重复的.what a fuck program ! 好吧,今天写一个文件去重功能 ...

  4. 清理 Docker 占用的磁盘空间

    Docker 很占用空间,每当我们运行容器.拉取镜像.部署应用.构建自己的镜像时,我们的磁盘空间会被大量占用. 如果你也被这个问题所困扰,咱们就一起看一下 Docker 是如何使用磁盘空间的,以及如何 ...

  5. 4.2 K8S超级完整安装配置

    前言: 采坑 k8s有3种安装方式,如下所示: minikube:这是一个k8s集群模拟器,只有一个节点的集群,只为了测试使用,master和node都在一台机器上 直接使用带有容器功能的云平台安装: ...

  6. jmeter参数化文件路径问题

    问题 win下做好的带参数化文件的脚本,放到linux下运行,由于参数化文件路径不正确,导致脚本运行失败,如果解决这个问题呢? 方案一:参数化路径 比如,参数化文件我放到jmeter的bin目录下,参 ...

  7. Linux安装ms-office

    https://ittutorials.net/open-source/linux/installing-microsoft-office-in-ubuntu/

  8. 思迈特软件Smartbi的特色功能有哪些?

    Smartbi产品价值: 从最终用户角度 管理层:KPI监控.风险预警.绩效考核.大屏展示,移动分析,实现经营管理主题(财务.销售.人事.绩效等)的直观监控,为经营管理提供决策支持 分析人员:拖拽式的 ...

  9. go面试集锦1

    目录 1.go优缺点 2.go中常量是怎么实现 3.go的值传递和引用 4.go struct能不能比较 5.go协程线程安全吗 6.go中关键字 7.make和new区别 8.defer 9.生产者 ...

  10. Java -- int与String相互转换

    int转换为String 使用Integer的静态方法 Integer.toString(int num); 空值会抛出NullPointerException异常 使用String的静态方法 Str ...