JVM运行时数据区

Java和C++的区别,体现在自动内存分配垃圾收集技术

JVM在执行Java程序时,会将它管理的内存分为若干个不同的数据区域。

这些区域有各自的作用范围以及生命周期:

  • 线程私有的区域,随着用户线程的启动和结束而建立和销毁。
  • 线程共享的区域,随着虚拟机进程的启动而一直存在,JVM结束后销毁。

1、程序计数器

程序计数器(Program Counter Register)是一块较小的内存空间,可以看做当前线程执行的字节码的行号指示器。是线程私有的。

JVM的字节码解释器工作时,就是通过改变这个计数器的值,来选取下一条需要执行的字节码指令。它是程序控制流的指示器。

1、为什么PC是线程私有的

首先,这个东西必须存在,因为肯定要记录下一条执行的指令是什么。

如果把这个东西做成线程共享的,那它的含义就是,当前正在执行的这个线程,下一条要执行的指令的地址

那么如果要发生线程上下文切换,新的线程必须告诉JVM,它的下一条指令的地址,同时,被切换走的那个线程也要保存它的下一条指令的地址

因此,为了线程切换后能恢复到上次执行的位置,就必须有线程私有的程序计数器。

2、PC的值

  • 如果线程执行的是一个Java方法,PC记录的是正在执行的虚拟机字节码指令的地址。
  • 如果线程执行的是一个Native方法,PC的值为空

PC这块内存区域,是唯一一个没有规定任何 OutOfMemoryError 情况的区域,永远不会发生内存溢出。

3、PC的作用

它的效果就是保存了下一条要执行的字节码指令地址,但是有两个作用:

  • 在本线程内:JVM的字节码解释器通过程序计数器来读取指令,所以PC可以进行程序的流程控制,比如顺序、循环、分支
  • 在多线程的情况下:程序计数器用于记录每个线程执行的位置,从而当线程被切换回来的时候能够得知该运行哪一条指令

2、虚拟机栈

虚拟机栈(VM Stack)也是线程私有的。

虚拟机栈描述的是Java方法执行的线程内存模型:

  • 每个方法被执行时,JVM都会同步创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息
  • 每个方法被调用直到执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

局部变量表

通常说的,JVM中的“栈内存”,指的就是此处的虚拟机栈,或专指虚拟机栈中局部变量表部分。

局部变量表存放了编译期可知的局部变量的内容,包括基本类型和对象引用、returnAddress类型(指向一条字节码指令的地址)

局部变量表所需的内存空间在编译期间完成分配。局部变量表的基本存储单位是“局部变量槽(Slot)”。

进入一个方法时,这个方法需要多大的局部变量空间是完全确定的(槽数确定),在方法运行期间不会改变局部变量表的大小。

这个内存区域存在两类异常:

  • StackOverflowError:线程请求的栈深度大于虚拟机允许的深度

  • OutOfMemoryError:线程申请栈空间失败,内存不够。

    (HotSpot不支持栈容量动态扩展,只要线程申请栈空间成功就不会在运行过程中发生OOM)

3、本地方法栈

作用和虚拟机栈类似,不过虚拟机栈是为Java方法服务的,而本地方法栈是为Native方法服务的。

这部分没有强制规定,HotSpot虚拟机直接把虚拟机栈和本地方法栈合二为一了

4、堆

堆(Heap)是JVM管理内存中最大的一块,被所有线程共享,在虚拟机启动时创建。

堆的唯一目的就是存放对象实例,大多数对象实例都存在这里

堆是垃圾收集器管理的内存区域,所以也被叫做“GC堆”(垃圾堆)。

堆占用的内存空间是可以扩展的,用这两个参数设定:

-Xmx // 设置最大内存
-Xms // 设置最小内存

如果堆的内存不足(堆上没有空间进行实例分配,且无法往大扩展),就会抛出 OutOfMemoryError 异常。

1、堆内存是怎么细分的

堆中可以细分为新生代和老年代,其中新生代又分为Eden区、From Survivor区、To Survivor区,默认比例是8:1:1,可以调整。

5、方法区

方法区(Method Area)也是线程共享的。

它用于存储已经被虚拟机加载的类型信息、常量、类的静态变量、JIT 即时编译器编译后的代码缓存等数据

方法区属于堆的一个逻辑部分,但要和堆区分开理解。

1、方法区的具体实现

并未规定具体实现方式,可以由虚拟机自行实现。

在JDK 8以前,HotSpot选择使用“永久代”实现方法区,这样可以让垃圾回收器也管理这部分内存,不用专门为这个空间写一个垃圾回收策略。但这样也有弊端,使得更容易发生内存溢出,因为永久代有内存上限

在JDK 6时,已经放弃使用永久代,逐步改为使用“本地内存”来实现方法区。

在JDK 7,已经把原本放在永久代的字符串常量池、静态变量等移出

到了JDK 8,完全废弃了永久代的概念,把内容全部移到了“元空间”中。

垃圾回收行为在方法区比较少见。但如果方法区内存不足,也会抛出 OutOfMemoryError 异常。

比如频繁使用动态代理创建出一堆类型,就会占据方法区内存

2、方法区和永久代的关系

《Java 虚拟机规范》只是规定了有方法区这么个概念和它的作用,并没有规定如何去实现它。

永久代就是HtoSpot对方法区的一种实现,其他虚拟机中是没有永久代的。

3、为什么要舍弃永久代,使用元空间

  • 永久代有内存上限,由JVM管理,无法进行调整,容易发生内存溢出。元空间在直接内存中,直接内存是受本机可用内存的影响,相对更不容易内存溢出
  • 元空间是方法区的实现,里面存放了类的元数据。元空间更大,那么能加载的类就更多了
  • 在 JDK8,合并 HotSpot 和 JRockit 的代码时, JRockit 从来没有⼀个叫永久代的东西, 合并之后就没有必要额外的设置这么一个永久代

6、运行时常量池

运行时常量池(Runtime Constant Pool)是方法区的一部分

Class文件中有“常量池表(Constant Pool Table)”,用于存放编译器生成的各种字面量与符号引用,在类加载完成后,这部分内容会存放在方法区的运行时常量池中。

运行时常量池具备动态性。Java语言并不要求常量一定只有编译期才能产生,即并不是只有Class文件中常量池表的内容能进入方法区的运行时常量池,运行期间也可以将新的常量放入常量池,比如String类的intern()方法。

运行时常量池受到方法区内存的限制,如果无法申请到足够的内存,也会抛出 OutOfMemoryError 异常。

存放的位置

  • 在JDK1.7前,运行时常量池+字符串常量池是存放在方法区的永久代中
  • 在JDK1.7中,字符串常量池从方法区移到堆中,运行时常量池还保留在方法区中
  • 在JDK1.8中,使用元空间实现方法区,此时字符串常量池依然保留在堆中,运行时常量池依然保留在方法区中,但此时的方法区处于元空间

7、直接内存

JDK1.8之后,方法区放在了元空间中,元空间就在直接内存中。

直接内存(Direct Memory)不是JVM运行时数据区的一部分,但也被频繁使用,也可能导致OOM。

在JDK 1.4中加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)和缓冲区(Buffer)的I/O方式。

它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆内的DirectByteBuffer对象作为这块内存的引用进行操作。这样就能提高性能,避免了在Java堆和Native堆中来回复制数据。

直接内存受到主机总内存(物理内存、分页文件)的限制,如果设置得比实际内存更大,在动态扩展时就会发生内存不足,从而到最后OOM。

8、总结

JVM将内存主要分为了两大部分:。其中堆是线程共享的,而栈是线程私有的。

  • 堆:用于存储对象实例
  • 栈:服务于每个线程方法的执行。
    • 每个方法执行时,JVM会同步创建一个栈帧,存储局部变量表、操作数栈、动态链接、方法出口等信息。
    • 一个方法的执行过程,对应着一个栈帧的入栈和出栈过程。

栈分成了两部分:

  • 虚拟机栈:面向Java方法
  • 本地方法栈:面向Native方法

要记录下一条执行的指令位置,并且控制线程的切换,需要设计一个线程私有的程序计数器

  • 程序计数器:
    • 负责存放当前线程的字节码执行位置。字节码解释器根据PC的值来选取字节码指令去执行。
    • 有两个作用:进行程序流程控制、保存上次执行到的字节码指令,线程切换回来后接着执行,所以它是线程私有的

HotSpot虚拟机在堆上额外开辟了一块内存,作为方法区

  • 方法区:
    • JDK1.8之前在堆上的永久代中,JDK1.8之后在直接内存的元空间中。
    • 用于存储已经被类加载的类、常量、类的静态变量、JIT 即时编译器的代码缓存

为了对常量进行优化,在方法区中开辟了运行时常量池

  • 运行时常量池:是方法区的一部分,存放编译器生成的各种字面量与符号引用

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/19383.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2023网络安全十大顶级工具

从事网络安全工作,手上自然离不开一些重要的网络安全工具。今天,分享10大网络安全工具。 一、Kali Linux Kali 是一个基于 Debian 的 Linux 发行版。它的目标就是为了简单:在一个实用的工具包里尽可能多的包含渗透和审计工具。Kali 实现了这…

MySQL基础(二十二)逻辑架构

1.逻辑架构剖析 1.1 第1层:连接层 系统(客户端)访问MySQL服务器前,做的第一件事就是建立TCP连接。 经过三次握手建立连接成功后,MySQL服务器对TCP传输过来的账号密码做身份认证、权限获取。 用户名或密码不对&#…

Redis 五大基本数据类型常见命令

一、redis中的常见数据结构 Redis共有5种常见数据结构,分别字符串(STRING)、列表(LIST)、集合(SET)、散列(HASH)、有序集合(ZSET)。 二、redis中五大基本数据类型介绍 字符串(Str…

尚硅谷JUC

文章目录 1. 什么是JUC1.1 JUC简介1.2 进程和线程基本概念2.1 Synchronized2.1.1 Synchronized关键字2.1.2 synchronized实现三个线程卖30张票 2.2 Lock2.2.1 什么是Lock2.2.2 使用Lock实现买票功能2.2.3 两者的区别 3. 线程间通信及定制化通信3.1 使用synchronized实现线程之间…

Hive语言

一、Hive的DDL语言(数据库、数据表的增删改查操作) 二、Hive的DQL语言(数据库查询语言) 2.1Hive七子句 聚合函数:count()、sum()、max()、min()、avg()可以单独使用。(缩写:cs mm a) 2.1.1 分区查询与分区裁剪 SELEC…

女生学习软件测试怎么样?

在IT技术行业,女生学习还是有很大优势的。女生相较于男生更有耐心,包容性强,心思细腻,对细节把控更好,同时还能帮助团队男女平衡,活跃气氛。 编程是一个只要你肯学习就会有回报的行业,不论男生…

ResourceManager HA 原理

简介 为了解决 Yarn 中 ResourceManager 的单点故障问题,在 Hadoop 2.4 中新增了 ResourceManager HA 的能力, 该文章基于 Hadoop 3.1.1 进行讲解。 1.1. 名词定义 全称简称备注ResourceManagerRmZookeeperZK ResourceManager Ha 架构 ResourceMana…

前端工程化 搭建私有组件库 组件从开发到发布私有npm仓库的全过程

前言 基于Vue3.0 TS的组件从开发组件库到发布私有npm仓库的全过程 环境 这里列出本文所使用的环境版本 vue 3.0 vue/cli 4.5.9 nodeJs 14.15.1 npm 6.14.8 vue --version vue/cli 4.5.9 npm -v 6.14.8 node -v v14.15.1 步骤 创建项目 使用 vue-cli 创建一个 vue3 项目&a…

mysql的高级查询语句

1.本文前言 数据库是用来存储数据,更新,查询数据的工具,而查询数据是一个数据库最为核心的功能,数据库是用来承载信息,而信息是用来分析和查看的。所以掌握更为精细化的查询方式是很有必要的。本文将围绕数据的高级查…

C++类和对象(中)

目录 1.类的6个默认成员函数 2.构造函数 2.1构造函数的概念 2.2构造函数的重载 2.3默认构造函数 2.4总结 3.析构函数 3.1析构函数的概念 3.2编译器自动生成的析构函数会做那些事情呢? 3.3析构函数的析构顺序 4.拷贝构造函数(复制构造函数&am…

用ChatGPT三分钟免费做出数字人视频- 提升自媒体魅力

用ChatGPT三分钟免费做出数字人视频- 提升自媒体魅力 一、ChatGPT产生文案二、腾讯智影网站三、选择一个2D数字人四、粘贴文本五、编辑自定义,合成六、资源七、其他数字人平台推荐八、生成视频预览 本教程收集于:AIGC从入门到精通教程汇总 操作指引 Ch…

哪个牌子的电视盒子好用?罗鹏数码盘点2023电视盒子排名

电视机资源少、卡顿,配置不足的时候只需要安装一台电视盒子就可以解决这些问题,不需要花费大价钱更换电视机。那么,你知道哪个牌子的电视盒子好用吗?今天罗鹏就来详细聊聊这个话题,分享2023最新电视盒子排名。 一&…

gitlab服务器发送邮件配置

1.修改gitlab的配置文件: vim /etc/gitlab/gitlab.rb 这里具体的gitlab.rb文件所在路径需要根据实际的来 找到如下图所示的部分,放开注释,修改配置,此处我用的发件邮箱是QQ邮箱,所以域名配置都是qq.com,…

图表控件Stimulsoft 2023.2 带来极致深色主题, 一起来看看还有哪些亮点?

Stimulsoft Reports 是一款报告编写器,主要用于在桌面和Web上从头开始创建任何复杂的报告。可以在大多数平台上轻松实现部署,如ASP.NET, WinForms, .NET Core, JavaScript, WPF, Angular, Blazor, PHP, Java等,在你的应用程序中嵌入报告设计器…

clickhouse的嵌套数据结构Tuple、Array与Nested类型介绍和使用示例

文章目录 Tuple类型Array类型Nested类型使用示例单独使用Tuple数组嵌套 Array(Tuple)Nested类型 生产使用:分组查询 Tuple类型 Tuple是ClickHouse数据库中的一种数据类型,它允许在一个字段中存储由不同数据类型组成的元组(tuple)。元组可以包含任意数量…

快速了解C语言的基本元素

C语言是一种编程语言,和其它语言一样,也定义了自己的语法和词汇。学习C语言,首先要学习C语言的词汇,再学习C语言的语法规则,然后由词汇构成语句,由语句构成源程序,源程序也称为源代码或代码&…

ChatGPT :国内免费可用 ChatGPT +Midjourney绘图

前言 ChatGPT(全名:Chat Generative Pre-trained Transformer),美国OpenAI 研发的聊天机器人程序 ,于2022年11月30日发布 。ChatGPT是人工智能技术驱动的自然语言处理工具,它能够通过理解和学习人类的语言来…

【MySQL】绪论 MySQL工作环境

文章目录 实验内容实验步骤实验内容 MySQL命令MySQL 的启动与关闭MySQL 管理备份和还原数据库navicat工具使用实验步骤 1. MySQL命令 (1)查看MySQL基本命令 (2)查看MySQL版本信息 2. MySQL的启动与关闭 (1)启动MySQL服务器 (2)测试服务器启动成功 (3)合法用

stream笔记

1、 创建流stream 1.1、 Stream 的操作三个步骤 1.2、 stream中间操作 1.2.1 、 limit、skip、distinct 1.2.2、 map and flatMap 1.2.3、 sort 自然排序和定制排序 1.3、 add and andAll difference: 1.4、 终止操作 1.4.1、 allmatch、anyMatch、noneMatch、max、min…

前端开发中,定位bug的几种常用方法

目录 第一章 前言 第二章 解决bug的方法 2.1 百度 2.2 有道翻译 2.3 debugger 2.4 console.log 日志打印 2.5 请求体是否携带参数 2.6 注释页面渲染代码 2.7 其他 第三章 尾声 备注:该文章只是本人在工作/学习中常用的几种方法,如果有不对大家…