JVM学习笔记六:运行时数据区之堆
目录
概述
堆空间内部结构
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。
对象在堆中的分配过程

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

上面的描述只是从宏观的角度描述了对象在堆中的内存分配,接下来仔细考虑以下几个问题:
具体的分配方式是什么?
对于第一个问题,首先需要清楚的是,对象所需的内存在类加载阶段完成后便可确定下来。为对象分配内存实际上就是将一块内存从java堆中划分出来存放这个对象。如果java堆中的内存是绝对规整的,即所有用过的内存放置在一边,所有没用过的内存放置在另一边。那么我们可以很方便的使用一个中间指针来分配内存,新的对象到来了中间指针就往空闲内存方向移动新的对象的内存大小的距离即可。这种分配方式称为“指针碰撞”(Bump The Pointer)。但是如果java堆中的内存并不是规整的,已使用过的和未使用过的内存交织在一起,就不能使用指针碰撞的方式分配内存了,虚拟机就需要维护一个列表,记录哪些内存块是可用的,分配时从列表中找到一块足够大的空间划分给对象即可,并更新列表上的记录,这种分配方式称为“空闲列表”(Free List)。选择哪种分配方式取决于java堆是否规整,而java堆是否规整又取决于所采用的垃圾收集器是否带有空间压缩整理的能力决定。
对象的分配是很频繁的操作,并发情况下是线程安全的吗?
对于第二个问题,对象创建时并发情况下可能出现正准备分配给A对象的内存在指针还没来得及分配时,B对象又使用了这一块内存区域的情况。解决这个问题有两种可选方案:第一种就是对分配内存空间的动作进行同步处理,虚拟机采用的是CAS配上失败重试的方式来保证更新操作的原子性。另一种方式是把内存分配的动作按照线程划分在不同的空间中进行,给每一个线程在java堆中预先分配一小块内存,称为本地线程分配缓冲,线程要在堆中分配内存,首先在各自的本地缓冲区中分配,本地缓冲区用完了,分配新的缓冲区时才需要同步锁定。
相关文章:
JVM学习笔记六:运行时数据区之堆
目录 概述 堆空间内部结构 JDK7版本 JDK8版本 堆空间的内存划分 堆空间大小设置参数 概述 Java堆是虚拟机所管理的内存中最大的一块,其在JVM启动时即被创建,并且空间大小也被确定(这里是不考虑Java8之后以本地内存来实现的元空间&…...
usb闪存驱动器数据恢复该怎么进行?3个方法总结
“怎么办?我的USB驱动器不知道因为什么原因,里面的数据、文件都消失了。有没有什么方法在没有进行备份的情况下恢复从U盘丢失的数据?” USB驱动器作为最常用的存储移动设备,里面保存着各种文件数据。但是有时会出现损坏而导致数据…...
DAX 微信 markdown 编辑器
DAX 微信 markdown 编辑器 一、致谢 感谢开源项目: md wechat-format 感谢 WordPress 插件 Mine云点播 作者 mine27 的指导。 二、如何使用 打开如下地址,直接编辑,可以实时看到符合微信公众号排版的效果。 推荐访问:https://j…...
湖南中创教育为学员提供方便快速的退费服务
2006年,湖南中创教育科技有限公司创始人团队开始创业进入职业教育行业;2014年公司正式成立,组建专业团队并转型升级“互联网”,进入在线教育行业。 自主研发“中创网校”学习平台,为学员提供了集直播、视频回放复习、…...
Java 给视频添加背景音乐 | Java工具
目录 前言 Maven依赖 环境依赖 代码 总结 前言 本文提供给视频添加背景音乐的java工具,一如既往的实用主义。 Maven依赖 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.1.1…...
【JUC2022】第二章 多线程锁
【JUC2022】第二章 多线程锁 文章目录【JUC2022】第二章 多线程锁一、乐观锁与悲观锁1.悲观锁2.乐观锁二、八锁案例1.标准情况,有a、b两个线程,请问先打印邮件还是短信【结果:邮件】2.sendEmail方法中加入暂停3秒钟,请问先打印邮件…...
快学会这个技能-.NET API拦截技法
大家好,我是沙漠尽头的狼。 本文先抛出以下问题,请在文中寻找答案,可在评论区回答: 什么是API拦截?一个方法被很多地方调用,怎么在不修改这个方法源码情况下,记录这个方法调用的前后时间&…...
stm32f407探索者开发板(十八)——串口通信实验讲解(USART_RX_STA流程图详解)
文章目录一、uart_init(串口初始化)二、USART1_IRQHandler(串口1中断服务程序)三、main.c(主函数)四、关于printf的支持一、uart_init(串口初始化) 就是根据上一篇的一样的步骤&…...
Hystrix资源隔离
目录资源隔离使用资源隔离的好处基于Hystrix实现微服务中资源隔离基于Hystrix线程池隔离实现资源隔离利用 HystrixCommand 获取单条数据利用 HystrixObservableCommand 批量获取数据基于 Hystrix 信号量机制实现资源隔离资源隔离 资源隔离是什么? 资源隔离是指把对…...
字符串(一)-- LeetCode[3] 无重复字符的最长子串
1 无重复字符的最长子串 1.1 题目描述 给定一个字符串 s ,请你找出其中不含有重复字符的最长子串的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例 2: 输入: s “bbbbb” 输出: 1 解释…...
Qt中修改界面类的类名时需要注意的几个修改点
有些时候因为一些原因,需要修改Qt中创建的界面类,需要特别注意几个修改点。 比如将test类修改为test2类 修改test.h名称为test2.h文件;修改test.cpp名称为test2.cpp文件;修改test.ui名称为test2.ui文件;修改pro文件中…...
【Spring6】| Spring启示录、Spring概述
目录 一:Spring启示录 1. OCP开闭原则 2. 依赖倒置原则DIP 3. 控制反转IoC 二:Spring概述 1. Spring简介 2. Spring8大模块 3. Spring特点 一:Spring启示录 引言:前面我们已经学习了三层架构:表示层、业务层、…...
react源码中的fiber架构
先看一下FiberNode在源码中的样子 FiberNode // packages/react-reconciler/src/ReactFiber.old.js function FiberNode(tag: WorkTag, pendingProps: mixed, key: null | string, mode: TypeOfMode, ) {// Instancethis.tag tag;this.key key;this.elementType null;t…...
C++类和对象-继承多态
继承 继承是面向对象三大特性之一 定义类时,下级别的成员除了拥有上一级的共性,还有自己的特性,就可以考虑使用继承的技术,减少代码的重复 继承的基本语法 语法:class 子类 : 继承方式 父类 子类也被成为派生类父类…...
appium自动化测试
获取应用包名和入口activity:aapt命令 aapt目录: 安卓sdk的build-tools目录下(如果要在cmd里直接运行,要配置环境变量,否则需要在aapt所在目录下打开cmd) 示例: adt-bundle-windows-x86_64-20140702\sdk\build-too…...
打印流、转换流、数据流 、随机访问流
Java知识点总结:想看的可以从这里进入 目录5、打印流6、转换流7、数据流8、随机访问流5、打印流 实现将基本数据类型的数据格式转化为字符串输出,它们提供了一系列重载的print()和println()方法,用于多种数据类型的输出,这种流不会…...
Java的4种访问权限?
1、public: 所修饰的类、变量、方法,在内外包均具有访问权限;2、protected: 这种权限是为继承而设计的,protected所修饰的成员,对所有子类是可访问的,但只对同包的类是可访问的,对外…...
APP任务模块功能借助php-resque实现业务解耦
先上设计图 说明:任务模块分一次性任务和每日任务,可能还包括男女用户任务区分 处理步骤: 一、同步任务数据库 1.1、任务列表数据库 1.2、完成任务数据库 二、搭建即时消息队列 一、composer require resque/php-resque二、因为服务器red…...
怎么做,才能在职场中晋升?
1 主动原则:主动做事 工作要积极主动,刚进入职场的同学,以为“服从命令听指挥”“领导指哪打哪”就是积极主动,结果易养 1.1 不好习惯 ① 认为主管肯定会帮你搞定晋升 你可能非常信任主管,认为自己只要把主管安排的…...
Vulnhub靶场----2、DC-2
文章目录一、环境搭建二、渗透流程三、思路总结一、环境搭建 DC-2下载地址:https://download.vulnhub.com/dc/DC-2.zip kali:192.168.144.148 DC-2:192.168.144.150 添加hosts文件:192.168.144.150 DC-2 二、渗透流程 nmap -A -…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
