JVM学习笔记六:运行时数据区之堆

news2024/11/24 0:14:05

目录 

概述

堆空间内部结构

JDK7版本

JDK8版本

堆空间的内存划分 

堆空间大小设置参数


概述

Java堆是虚拟机所管理的内存中最大的一块,其在JVM启动时即被创建,并且空间大小也被确定(这里是不考虑Java8之后以本地内存来实现的元空间,在Java8之前可以很确切的这么说,个人认为如果将其与元空间比较意义并不大),同时也是所有线程共享的一块内存区域,此内存区域的唯一目的就是存放对象实例,”几乎“所有的对象实例都在这里分配(注意这里的“几乎”二字,除了堆上分配,还可以栈上分配,这依赖于逃逸分析技术的提高)。

堆内存被分为了:新生代(Young)、老年代(Old),新生代又划分为:伊甸区(Eden),幸存者0区(Survivor 0)和幸存者1区(Survivor 1)(有的资料也写作:from 区和 to 区)。

从Java堆的内存划分便可以体现出Java堆是内存回收的重点地区,这种划分形式也是为了更高效的实现垃圾回收。

堆空间内部结构

我们平常讨论的JVM如果没有特别指明类型的话,默认都是以HotSpot虚拟机而言,下文也是入此。 

说到堆空间的内部结构,需要根据JDK的版本而定,在JDK7及之前,HotSpot虚拟机选择将方法区和堆空间合并实现,称作永久代,其好处就是省略了专门为方法区编写代码,可以复用堆空间的代码。但是以现在的眼光来看,还是存在诸多弊端。所以在JDK8改为用本地内存来实现方法区,称作元空间。

JDK7版本

方法区被叫做永久代,并且和堆空间合并一起实现。其实在JDK7时开发人员就已经意识到了缺陷并且在开始解决了,JDK7时将字符串常量池、静态变量从永久代中存放到堆空间中。

JDK8版本

移除永久代,用本地内存实现方法区改称元空间。其中原本存放在永久代中的类型信息、字段、方法、常量保存在本地内存的元空间,字符串常量池和静态变量依旧保存在堆中(堆是内存回收的重点区域,而字符串是开发中经常用到的,所以也需要频繁的清理,所以字符串常量池放在堆空间是合理的)。

堆空间的内存划分 

堆空间被分为了新生代、老年代,新生代被划分为伊甸区、幸存者0区、幸存者1区。

堆内存默认结构占比:

新生代:老年代 = 1:2

伊甸区:幸存者0区:幸存者1区 = 8:1:1

堆空间大小设置参数

Java堆区用于存储Java对象实例,堆的大小在JVM启动时就已经设定好了,可以在启动时设置启动参数来指定堆空间的大小。

  • “-Xms"用于表示堆区的起始内存,等价于-XX:InitialHeapSize
  • “-Xmx"则用于表示堆区的最大内存,等价于-XX:MaxHeapSize

一旦堆区中的内存大小超过“-Xmx"所指定的最大内存时,将会抛出OutOfMemoryError异常。

通常会将-Xms和-Xmx两个参数配置相同的值,其目的是为了能够在ava垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小,从而提高性能。

堆空间分代思想

上文已经提到了默认情况下堆空间的分代结构以及具体的内存大小划分。这种分代形式主要跟垃圾回收机制有关,垃圾回收机制大多数都遵循了分代收集的原则:

  • 弱分代假说:绝大多数对象都是朝生熄灭的。
  • 强分代假说:熬过越多次垃圾收集的对象就越难以消亡。
  • 跨代引用假说:跨代引用相对于同代引用来说仅占极少数。

可以粗略的理解为:存放在堆空间的对象需要经常清理,但是对象与对象之间的存活周期也是不同的。那些存活周期比较长的对象存放在老年代中,朝生熄灭的对象存放在新生代中。可以通过设置对两个代的垃圾扫描频率来达到更高的回收效率,新生代的对象朝生熄灭那么就需要经常清理,老年代的存活周期长可以降低频率提高效率。  

分代内存设置

设置新生代内存大小

“-XX:NewSize” 新生代的最小值

”-XX:MaxNewSize“ 新生代的最大值

“-XX:NewRatio” 设置新生代与老年代在堆空间的大小

"-XX:SurvivorRatio" 设置幸存者区和伊甸区的大小比值(注意:幸存者区有两个)

例1:-XX:NewSize=10M -XX:MaxNewSize=20M 设置新生代最小值为10M,最大值为20M。

例2:-XX:NewRatio=4 设置新生代和老年代的比值为4,即 新生代 :老年代 = 1 :4

例3:-XX:SurvivorRatio=8 表示 幸存者区和伊甸区的大小比例为 1 :8。

对象在堆中的分配过程

上面的流程图表示的是对象在堆中内存分配的过程,内存分配和内存回收密切相关。

  1. 创建的对象先放伊甸园区,此区有大小限制。
  2. 当伊甸园的空间填满时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收(MinorGC),将伊甸园区中的不再被其他对象所引用的对象进行销毁。再加载新的对象放到伊甸园区。(值得注意的是,幸存者区空间填满时并不会触发垃圾回收,对幸存者区的回收是在MinorGC中顺便做的事情)
  3. 然后将伊甸园中的剩余对象移动到幸存者0区。
  4. 如果再次触发垃圾回收,此时上次幸存下来的被放到幸存者0区的对象如果没有被回收,就会放到幸存者1区。(幸存者两个区之间是通过标记复制算法进行垃圾回收的)
  5. 如果再次经历垃圾回收,此时会重新放回幸存者0区,接着再去幸存者1区。
  6. 对象什么时候能够去到老年代?JVM默认是经历了15次垃圾回收之后。当然也可以设置参数来控制:设置 -Xx:MaxTenuringThreshold=N
  7. 当老年代内存不足时,再次触发GC:Major GC,进行养老区的内存清理。
  8. 若老年代执行了Major GC之后,发现依然无法进行对象的保存,就会产生OOM异常。

下图主要描述的是幸存者区之间的关系。 

上面的描述只是从宏观的角度描述了对象在堆中的内存分配,接下来仔细考虑以下几个问题:

具体的分配方式是什么?

对于第一个问题,首先需要清楚的是,对象所需的内存在类加载阶段完成后便可确定下来。为对象分配内存实际上就是将一块内存从java堆中划分出来存放这个对象。如果java堆中的内存是绝对规整的,即所有用过的内存放置在一边,所有没用过的内存放置在另一边。那么我们可以很方便的使用一个中间指针来分配内存,新的对象到来了中间指针就往空闲内存方向移动新的对象的内存大小的距离即可。这种分配方式称为“指针碰撞”(Bump The Pointer)。但是如果java堆中的内存并不是规整的,已使用过的和未使用过的内存交织在一起,就不能使用指针碰撞的方式分配内存了,虚拟机就需要维护一个列表,记录哪些内存块是可用的,分配时从列表中找到一块足够大的空间划分给对象即可,并更新列表上的记录,这种分配方式称为“空闲列表”(Free List)。选择哪种分配方式取决于java堆是否规整,而java堆是否规整又取决于所采用的垃圾收集器是否带有空间压缩整理的能力决定。

对象的分配是很频繁的操作,并发情况下是线程安全的吗?

对于第二个问题,对象创建时并发情况下可能出现正准备分配给A对象的内存在指针还没来得及分配时,B对象又使用了这一块内存区域的情况。解决这个问题有两种可选方案:第一种就是对分配内存空间的动作进行同步处理,虚拟机采用的是CAS配上失败重试的方式来保证更新操作的原子性。另一种方式是把内存分配的动作按照线程划分在不同的空间中进行,给每一个线程在java堆中预先分配一小块内存,称为本地线程分配缓冲,线程要在堆中分配内存,首先在各自的本地缓冲区中分配,本地缓冲区用完了,分配新的缓冲区时才需要同步锁定。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

连续时间信号与离散时间信号

前言 《信号与系统》是一门很难的课,也是许多学校考研要考的专业课,由于每周只有两节课,所以每次上完都要及时的去复习,这里参考的教材是奥本海姆著作,刘海棠译,北京:电子工业出版社&#xff0…

实践数据湖iceberg 第四十课 iceberg的sql运维方式(合并文件、合并元数据、清理历史快照)

系列文章目录 实践数据湖iceberg 第一课 入门 实践数据湖iceberg 第二课 iceberg基于hadoop的底层数据格式 实践数据湖iceberg 第三课 在sqlclient中,以sql方式从kafka读数据到iceberg 实践数据湖iceberg 第四课 在sqlclient中,以sql方式从kafka读数据到…

只因小黑子:SVG

小黑子的SVG复习SFV画布1. 初始SVG2. SVG绘制矩形、圆形和椭圆形2.1 rect 矩形2.2 circle 圆形2.3 ellipse 椭圆4. SVG绘制线条、多边形和多线条4.1 line 线条4.2 polygon 多边形4.3 polyline 多线条5. SVG绘制文本 text6. SVG绘制路径 path7. SVG描边属性8. SVG 模糊和阴影效果…

MySQL安装配置教程(超级详细、保姆级)

一、 下载MySQL Mysql官网下载地址:https://downloads.mysql.com/archives/installer/ 选择想要安装的版本,点击Download下载 本篇文章选择的是5.7.31版本 二、 安装MySQL 选择设置类型 双击运行mysql-installer-community-5.7.31.0.msi,…

车载以太网 - 测试用例设计 - 时间参数 - 11

前面已经介绍过DoIP相关的时间参数信息,然而对于时间参数信息相关的测试用例该如何设计呢?个人认为这是用例中最好设计的一类,这类的用例只需要按照定义去设计写测试用例即可,难的是自动化脚本开发和手动测试执行。毕竟时间参数一般都是毫秒级的验证,就算是秒级的我们也很…

【项目管理】对管理的认识与思考

在进入职场一段时间后,我们不免会对管理有一些接触,可能会自己带团队、可能会到管理岗位等等;做管理重要的就是对于不同层级的管理。 管理是一门艺术,在谈到管理时,我们首先想到的应该是管人、带团队或者是一个部门或公…

matplotlib学习笔记(持续更新中…)

目录 1. 安装,导入 2. figure,axes(图形,坐标图形) 2.1 figure对象 2.2 axes对象 2.3 代码演示 2.3 subplot() 方法 3. 图表的导出 3.1 savefig() 方法 3.2 代码演示 1. 安装,导入 pip install m…

Python —— Windows10下配置Pytorch环境(完整流程)

最终效果 配置流程 一、下载安装显卡驱动 1、查看设备管理器显卡是否为NVIDIA,并确定显卡型号 2、根据显卡型号然后NVIDIA官网下载安装显卡驱动 下载完成后,双击一步一步执行即可。 3、安装完成驱动后,打开cmd终端输入"nvidia-smi"…

JVM学习笔记五:运行时数据区之本地方法栈

目录 概述 本地方法(Native Method) 使用本地方法的原因 本地方法栈 执行流程 概述 如果要了解本地方法栈的作用,首先需要了解本地方法库和本地方法接口。 本地方法接口是Java代码调用其他非Java代码的接口,本地方法库是其他…

观看课程领奖品!Imagination中国区技术总监全面解读 IMG DXT GPU

此前,我们发布了一系列关于 IMG DXT GPU 的介绍,为了让更多读者了解其背后的技术及应用方向,我们特别邀请 Imagination 中国区技术总监艾克录制全新在线课程,为大家全面解读IMG DXT GPU。 点击这里,马上注册观看&…

函数的栈帧的创建和销毁

文章目录本章主题:一.什么是函数栈帧1.什么是栈2.什么是函数栈帧二.理解函数栈帧能解决什么问题呢?三.函数栈帧的创建和销毁解析1.预备知识(1) 认识相关寄存器和汇编指令(2)栈帧空间的维护2.解析函数栈帧的…

uniapp 引入彩色symbol和 指令权限

uniapp 引入iconfont图标库彩色symbol 1,先去阿里巴巴矢量图标库登录 然后点击下载至本地 2.下载本地,然后解压文件夹 3.打开终端cmd命令窗口 npm安装全局包npm i -g iconfont-tools 4.终端切换到上面解压的文件夹里面,运行iconfont-too…

原理的学习

序参考的是这个书:Python神经网络编程 (豆瓣) (douban.com)小白,0基础,也看不懂其它更复杂的书……01.正向计算从左到右,根据输入值,得到输出值总览这就是神经元的数学形式:阈值函数sigmoid函数&#xff1a…

TIA博途_通过不定长数组实现冒泡排序的具体方法示例(封装FC全局库)

通过不定长数组实现冒泡排序的具体方法示例(封装FC全局库) 使用这种不定长数组时要注意,低版本的博途可能不支持这种方法(我自己尝试的V15版本时失败了,无法实现),本例中使用的是TIA博途V17版本。 具体步骤可参考如下: 如下图所示,打开博途后新建一个项目,添加一个12…

Java监听器的理解与实现

文章目录初识监听器Listener接口分类ServletContext监听器HttpSession监听器ServletRequest监听器Java代码实现ServletContextListenerServletContextAttributeListenerHttpSessionListenerHttpSessionAttributeListenerHttpSessionActivationListenerHttpSessionBindingListen…

在 4G 内存的机器上,申请 8G 内存会怎么样?

在 4GB 物理内存的机器上,申请 8G 内存会怎么样? 这个问题在没有前置条件下,就说出答案就是耍流氓。这个问题要考虑三个前置条件: 操作系统是 32 位的,还是 64 位的?申请完 8G 内存后会不会被使用&#x…

【机器学习】集成学习

1.什么是集成学习 集成学习的基本思想是结合多个学习器组合成一个性能更好的学习器。这类方法会训练多个弱学习器(基学习器)并将它们输出的结果以某种策略结合起来组成一个强学习器。 2.集成学习的几种方法 根据个体学习器的生成方式,集成学…

手把手教你用React Hook和TypeScript从零实现虚拟滚动列表组件

前言 k8s 全称 kubernetes,这个名字大家应该都不陌生,k8s是为容器服务而生的一个可移植容器的编排管理工具,集应用的部署和运维,负载均衡,服务发现和扩容,版本回滚于一身,越来越多的公司正在拥…

linux集群技术(二)--keepalived(高可用集群)(二)

案例1--keepalived案例2--keepalived Lvs集群1.案例1--keepalived 1.1 环境 初识keepalived,实现web服务器的高可用集群。 Server1: 192.168.26.144 Server2: 192.168.26.169 VIP: 192.168.26.190 1.2 server1 创建etc下的…

02-04 周六 图解机器学习 SVM 支持向量机分类学习

02-04 周六 图解机器学习 SVM 支持向量机分类学习时间版本修改人描述2023年2月4日11:15:16V0.1宋全恒新建文档 环境搭建 首先搭建jupyter环境,方便可视化 (base) rootnode33-a100:~# docker run --name sqh-learn -d -p 10088:8888 -it 10.101.12.128/framework/ju…