运行时数据区域

总览

JDK. 1.7 之后版本略有不同

Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。

有必要深入了解这块的内容,因为它将决定服务器性能,除此之外还有助于快速定位虚拟机的相关Error。

首先来对整个运行时区域有一个整体的认识。

如下图

JDK 1.7 之前:

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

  • 线程私有的(图中红色)

  • 线程共享的(图中绿色、蓝色)

概念扫盲

什么是栈帧(Stack Frame)

每一次函数的调用,都会在调用栈上维护一个独立的栈帧,每个独立的栈帧一般包括:

  • 函数的返回地址和参数
  • 临时变量
  • 函数调用的上下文

栈是从高地址向低地址延伸,一个函数的栈帧用ebpesp 这两个寄存器来划定范围。

ebp 指向当前的栈帧的底部,esp 始终指向栈帧的顶部。

  • ebp 寄存器又被称为帧指针(Frame Pointer)
  • esp 寄存器又被称为栈指针(Stack Pointer)

JVM常见出现两种错误

  • StackOverFlowError 若 Java 虚拟机栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前 Java 虚拟机栈的最大深度的时候,就抛出 StackOverFlowError 错误。
  • OutOfMemoryError Java 虚拟机栈的内存大小可以动态扩展, 如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常异常。

程序计数器

程序计数器占用较小的一块内存空间,每条线程都需要有一个独立的程序计数器,程序计数器用于记录当前线程执行的位置,从而当线程被来回切换的时候,能够知道该线程上次运行到哪儿了。

字节码解释器工作时通过改变这个计数器的值,来选取下一条需要执行的字节码指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。

它的生命周期随着线程的创建而创建,随着线程的结束而死亡。

程序计数器是唯一一个不会出现 OutOfMemoryError 的内存区域。

虚拟机栈

结构

虚拟机栈也是线程私有,而且生命周期与线程相同。

每个Java方法在执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息

局部变量表

  • 存放编译器可知的各种基本数据类型(boolean、byte等)
  • 对象引用(reference类型,它不等同于对象本身)
    • 可能是一个指向对象起始地址的引用指针
    • 也可能是指向另一个代表对象的句柄
    • 其他次对象相关的位置
  • returnAddress类型,指向了一条字节码指令的地址

方法是如何调用的

每一次函数调用都会有一个对应的栈帧被压入 Java 栈,每一个函数调用结束后,都会有一个栈帧被弹出。

Java 方法有两种返回方式:

  1. return 语句。
  2. 抛出异常。

不管哪种返回方式都会导致栈帧被弹出。

本地方法栈

主要为虚拟机使用到的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虚拟机-运行时数据区概述的更多相关文章

  1. 【JVM之内存与垃圾回收篇】运行时数据区概述及线程

    运行时数据区概述及线程 前言 本节主要讲的是运行时数据区,也就是下图这部分,它是在类加载完成后的阶段 当我们通过前面的:类的加载-> 验证 -> 准备 -> 解析 -> 初始化 ...

  2. 【JVM从小白学成大佬】2.Java虚拟机运行时数据区

    目录 1.运行时数据区介绍 2.堆(Heap) 是否可能有两个对象共用一段内存的事故? 3.方法区(Method Area) 4.程序计数器(Program Counter Register) 5.虚 ...

  3. 【JVM学习】2.Java虚拟机运行时数据区

    来源: 公众号: 猿人谷 这里我们先说句题外话,相信大家在面试中经常被问到介绍Java内存模型,我在面试别人时也会经常问这个问题.但是,往往都会令我比较尴尬,我还话音未落,面试者就会"背诵& ...

  4. 面试常问的 Java 虚拟机运行时数据区

    写在前面 本文描述的有关于 JVM 的运行时数据区是基于 HotSpot 虚拟机. 概述 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以 ...

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

    写在前面 本文描述的有关于 JVM 的运行时数据区是基于 HotSpot 虚拟机. 概述 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以 ...

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

    本文摘自深入理解 Java 虚拟机第三版 概述 Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟 ...

  7. JVM入门——运行时数据区

    这张图我相信基本上对JVM有点接触的都应该很熟悉,可以说这是JVM入门的第一课.其中的“堆”和“虚拟机栈(栈)”更是耳熟能详.下面将围绕这张图对JVM的运行时数据区做一个简单介绍. 程序计数器(Pro ...

  8. jvm理论-运行时数据区

    三大流行jvm sun HotSpot ibm j9 BEA JRockit Oracle 会基于HotSpot整合 JRockit. jvm运行时数据区 java虚拟机所管理的内存将会包括以下几个运 ...

  9. 《深入理解Java虚拟机》(二)Java虚拟机运行时数据区

    Java虚拟机运行时数据区 详解 2.1 概述 本文参考的是周志明的 <深入理解Java虚拟机>第二章 ,为了整理思路,简单记录一下,方便后期查阅. 2.2 运行时数据区域 Java虚拟机 ...

随机推荐

  1. 【海思】Hi3516A 运行sample_venc的demo内核奔溃(DDR问题)

    作者:李春港 出处:https://www.cnblogs.com/lcgbk/p/14514297.html 目录 一.前言 二.使用memtester对ddr进行压力测试 三.修改uboot的DD ...

  2. SQL练习——LeetCode解题和总结(1)

    只用于个人的学习和总结. 178. Rank Scores 一.表信息 二.题目信息 对上表中的成绩由高到低排序,并列出排名.当两个人获得相同分数时,取并列名次,且名词中无断档. Write a SQ ...

  3. Elasticsearch 复合查询——多字符串多字段查询

    前言 有时我们在搜索电影的时候,包含了多个条件,比如主演是周星驰,打分8分以上,上映时间是1990年~2001年的,那么Elasticsearch又该如何帮我们做查询呢?这里我们可以用 bool 查询 ...

  4. exe取消动态基址

    动态基址开启后,在动态调试是想要和ida静态分析中的地址对应还要进行一步计算,取消动态基址便可以剩下很多时间. 只要修改pe文件头中的Characteristics低位置1 1 typedef str ...

  5. 运维小姐姐说这篇Consul集群和ACL配置超给力(保姆级)

    前言 上一篇简单介绍了Consul,并使用开发模式(dev)进行流程演示,但在实际开发中需要考虑Consul的高可用和操作安全性,所以接着来聊聊集群和ACL的相关配置,涉及到的命令会在环境搭建过程中详 ...

  6. 【Azure 应用服务】App Service 在使用GIt本地部署,上传代码的路径为/home/site/repository,而不是站点的根目录/home/site/wwwroot。 这个是因为什么?

    问题描述 App Service 在使用GIt本地部署,上传代码的路径为/home/site/repository,而不是站点的根目录/home/site/wwwroot. 这个是因为什么? 并且通过 ...

  7. ES核心概念和原理

    ES:1:倒排索引 基于Document 关键词索引实现 . 根据关键词做索引 相关度 a. 数据结构 i. 包含关键词的Document List ii. 关键词在每个doc中出现的次数 词频 TF ...

  8. OpenCV图像处理中“投影技术”的使用

           本文区分"问题引出"."概念抽象"."算法实现"三个部分由表及里具体讲解OpenCV图像处理中"投影技术" ...

  9. java例题_18 乒乓球比赛(对手问题)

    1 /*18 [程序 18 乒乓球赛] 2 题目:两个乒乓球队进行比赛,各出三人.甲队为 a,b,c 三人,乙队为 x,y,z 三人.已抽签决定比赛名单. 3 有人向队员打听比赛的名单.a说他不和 x ...

  10. (数据科学学习手札115)Python+Dash快速web应用开发——交互表格篇(上)

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...