JVM堆详解, 了解不迷路

2023-11-02 20:20
文章标签 java jvm 详解 了解 迷路

本文主要是介绍JVM堆详解, 了解不迷路,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上周工作比较忙,又是上线, 又是加班的, 搞得学习进度拉下来很多。

上周也是有很大收获的, 自己上周, 学习到了一个牛逼的学习方法, 你通过我的学习笔记, 其实就可以看出来, 其中更多了很多自己的思考。

第一:论语士学习:我们通过目录结构, 去提问题, 和作者去对答案

第二:记忆曲线, 我觉得大家应该都知道, 那我们又如何打造自己的学习曲线, 整理自己学习到的东西不会忘记呢, 推荐一个神器, ankiapp, 通过程序化的推荐方式, 利用碎片话的时间, 帮助我们打造完成的知识体系

我们正在使用, 请大家跟我一起学习起来。 持续精进, 不断打造自己的知识体系。让自己越来越优秀。

1. JVM中的堆和栈有什么不同?

栈解决的程序运行问题,即程序如何执行,或者说如何处理数据;

堆解决的是数据存储问题,即就是数据如何放、放哪儿

2. 什么要把堆和栈分开, 这样设计有什么好处呢?

  1. 从设计角度, 堆存数据, 栈处理逻辑, 这样设计区分, 可以隔离和模块化, 分而治之的思想

  2. 共享内存(多线程访问一个对象),节省内存

  3. 栈的地址, 只能连续增加, 堆可以动态增加, 相互拆分, 栈关联堆的一个地址即可, 提高内存利用率

  4. 对象就是对债完美结合, 对象属性存储数据, 就是堆, 栈就是对象的方法

3. 堆中内存是如何划分的

1. 怎么区分老年代和年轻代

年轻代中的对象, 生命周期很短, 基本很快就死了, 也就是被GC了。

老年代中的对象, 都是一些老顽固, 经过15次回收的对象或者大对象才存到老年代中

从年轻代进入老年代

第一种的情况就是将躲过15次MinorGC的对象移动到老年代.

第二种就是动态年龄对象判断,既Survivor区的经历过两次GC的对象大小大于Survivor区容量的一半的时候,如Survivor区是100m,里面的对象之和大于50m.就将这些2次GC还存活的对象移入到老年代中去.

第三种就是大对象,还没有进入到新生代的时候就被移动到老年代,这里有个参数,为-XX:PretenureSizeThreshold,可以设置值,比如1m,那么再进入堆内存的时候,就会检查这个实例对象的大小,如果大于这个阈值,就直接进入到老年代.

2. 什么是Stop the World?

Full GC的时候, 就是Stop the World.

系统在进行垃圾回收的时候会暂停java程序的执行.直到垃圾回收完成.所谓jvm的迭代演进其实就是基本上就是在解决减少垃圾回收,和垃圾回收的时间尽可能的短.一起都取决于垃圾回收算法.

3. 堆内存中内存划分比例

老年代:年轻代 =  2:1

年轻代中:eden(伊甸区) :service0(幸存区0) :service1(幸存区1) = 8:1:1

jvm堆空间.jpg

4. 老年代和年轻代为什么是2:1

**默认的,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 **

( 该值可以通过参数 –XX:NewRatio 来指定 )

5. 为什么会有survivorto?

如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。老年代很快被填满,触发Major GC(因为Major GC一般伴随着Minor GC,也可以看做触发了Full GC)。老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多。你也许会问,执行时间长有什么坏处?频发的Full GC消耗的时间是非常可观的,这一点会影响大型程序的执行和响应速度,更不要说某些连接会因为超时发生连接错误了。好,那我们来想想在没有Survivor的情况下,有没有什么解决办法,可以避免上述情况:

方案优点缺点
增加老年代空间更多存活对象才能填满老年代。降低Full GC频率随着老年代空间加大,一旦发生Full GC,执行所需要的时间更长
减少老年代空间Full GC所需时间减少老年代很快被存活对象填满,Full GC频率增加

显而易见,没有Survivor的话,上述两种解决方案都不能从根本上解决问题。

我们可以得到第一条结论:Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生,Survivor的预筛选保证,只有经历16次Minor GC还能在新生代中存活的对象,才会被送到老年代。

6. 为什么要设置两个Servivor区

设置两个Survivor区最大的好处就是解决了碎片化

eden:survivorfrom:survivorto = 8:1:1

Java堆内存分为年轻代和老年代,其中, 年轻代分为Eden区和survival区,survival又分为fromSurvival和toSurvival。

为什么一个Survivor区不行?第一部分中,我们知道了必须设置Survivor区。假设现在只有一个survivor区,我们来模拟一下流程:刚刚新建的对象在Eden中,一旦Eden满了,触发一次Minor GC,Eden中的存活对象就会被移动到Survivor区。这样继续循环下去,下一次Eden满了的时候,问题来了,此时进行Minor GC,Eden和Survivor各有一些存活对象,如果此时把Eden区的存活对象硬放到Survivor区,很明显这两部分对象所占有的内存是不连续的,也就导致了内存碎片化。我绘制了一幅图来表明这个过程。其中色块代表对象,白色框分别代表Eden区(大)和Survivor区(小)。Eden区理所当然大一些,否则新建对象很快就导致Eden区满,进而触发Minor GC,有悖于初衷。

15.jpg

碎片化带来的风险是极大的,严重影响JAVA程序的性能。堆空间被散布的对象占据不连续的内存,最直接的结果就是,堆中没有足够大的连续内存空间,接下去如果程序需要给一个内存需求很大的对象分配内存。。。画面太美不敢看。。。这就好比我们爬山的时候,背包里所有东西紧挨着放,最后就可能省出一块完整的空间放相机。如果每件行李之间隔一点空隙乱放,很可能最后就要一路把相机挂在脖子上了。那么,顺理成章的,应该建立两块Survivor区,刚刚新建的对象在Eden中,经历一次Minor GC,Eden中的存活对象就会被移动到第一块survivor space S0,Eden被清空;等Eden区再满了,就再触发一次Minor GC,Eden和S0中的存活对象又会被复制送入第二块survivor space S1(这个过程非常重要,因为这种复制算法保证了S1中来自S0和Eden两部分的存活对象占用连续的内存空间,避免了碎片化的发生)。S0和Eden被清空,然后下一轮S0与S1交换角色,如此循环往复。如果对象的复制次数达到16次,该对象就会被送到老年代中。下图中每部分的意义和上一张图一样,就不加注释了。

16.jpg

上述机制最大的好处就是,整个过程中,永远有一个survivor space是空的,另一个非空的survivor space无碎片。

那么,Survivor为什么不分更多块呢?比方说分成三个、四个、五个?显然,如果Survivor区再细分下去,每一块的空间就会比较小,很容易导致Survivor区满,因此,我认为两块Survivor区是经过权衡之后的最佳方案。

7. 堆内存分配方法:

分配方法说明收集器
指针碰撞内存地址是连续的Serial和ParNew收集器
空闲列表内存地址是不连续的CMS收集器和Mark-Sweep收集器

8. 内存分配安全问题

在分配内存的同时, 存在线性安全问题, 即虚拟机给A线程分配内存过程中, 指针未修改, B线程可能同时使用了同样一块内存。

JVM中有两种解决办法:

  1. CAS, 比较和交换, CAS是乐观锁的一种实现, 所谓乐观锁就是, 每次不加锁而是假设没有冲突而去完成某项操作, 如果因为冲突失败就重试, 知道成功为止, 虚拟机采用cas配上失败重试的方式保证更新操作的原子性。

  2. TLAB, 本地线程分配缓冲:为每一个线程预分配一块内存, JVM在给线程中的对象分配内存时, 首先在TLAB分配, 当对象大于TLAB中的剩余内存或者TLAB内存耗尽时, 在采用上述的CAS进行内存分配

方案1在每次分配时都需要进行同步控制,这种是比较低效的。

方案2是HotSpot虚拟机中采用的,这种方案被称之为TLAB分配,即Thread Local Allocation Buffer。这部分Buffer是从堆中划分出来的,但是是本地线程独享的。

9. 对象的内存布局

对象在内存中存储的布局可以分为三个区域, 对象头(Header), 实例数据(Instance data)和对齐填充(padding).

1. 对象头

对象头包括两部分信息: 一部分是用于存储对象自身的运行数据,如haashCode, GC分代年龄, 锁状态标志, 线性持有的锁, 偏向线程ID, 偏向时间戳等。

另一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪一个类的实例。当对象是一个java数组的时候,那么对象头还必须有一块用于记录数组长度的数据,因此虚 拟机可以通过普通java对象的元数据信息确定java对象的大小,但是从数组的元数据中无法确定数组的 大小。

2. 实例数据

存储对象真正有效的信息

3. 对齐填充

这部分并不是必须要存在的, 没有特别的含义, 在jvm中对象的大小必须是8字节的整数倍, 而对象头也是8字节的倍数, 当对象实例数据部分没有对齐时, 就需要通过对齐填充来补全

10. 对象访问的方式

方式优点
句柄稳定, 对象被移动只要修改句柄中的地址
直接指针访问速度快, 节省了一次指针定位的开销
17.png
18.png
分享技术成长
创作不易.gif

这篇关于JVM堆详解, 了解不迷路的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/333068

相关文章

Python装饰器之类装饰器详解

《Python装饰器之类装饰器详解》本文将详细介绍Python中类装饰器的概念、使用方法以及应用场景,并通过一个综合详细的例子展示如何使用类装饰器,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录1. 引言2. 装饰器的基本概念2.1. 函数装饰器复习2.2 类装饰器的定义和使用3. 类装饰

SpringBoot UserAgentUtils获取用户浏览器的用法

《SpringBootUserAgentUtils获取用户浏览器的用法》UserAgentUtils是于处理用户代理(User-Agent)字符串的工具类,一般用于解析和处理浏览器、操作系统以及设备... 目录介绍效果图依赖封装客户端工具封装IP工具实体类获取设备信息入库介绍UserAgentUtils

Spring 中的循环引用问题解决方法

《Spring中的循环引用问题解决方法》:本文主要介绍Spring中的循环引用问题解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录什么是循环引用?循环依赖三级缓存解决循环依赖二级缓存三级缓存本章来聊聊Spring 中的循环引用问题该如何解决。这里聊

MySQL 中的 JSON 查询案例详解

《MySQL中的JSON查询案例详解》:本文主要介绍MySQL的JSON查询的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录mysql 的 jsON 路径格式基本结构路径组件详解特殊语法元素实际示例简单路径复杂路径简写操作符注意MySQL 的 J

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

Spring Boot中JSON数值溢出问题从报错到优雅解决办法

《SpringBoot中JSON数值溢出问题从报错到优雅解决办法》:本文主要介绍SpringBoot中JSON数值溢出问题从报错到优雅的解决办法,通过修改字段类型为Long、添加全局异常处理和... 目录一、问题背景:为什么我的接口突然报错了?二、为什么会发生这个错误?1. Java 数据类型的“容量”限制

Java对象转换的实现方式汇总

《Java对象转换的实现方式汇总》:本文主要介绍Java对象转换的多种实现方式,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Java对象转换的多种实现方式1. 手动映射(Manual Mapping)2. Builder模式3. 工具类辅助映

SpringBoot请求参数接收控制指南分享

《SpringBoot请求参数接收控制指南分享》:本文主要介绍SpringBoot请求参数接收控制指南,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring Boot 请求参数接收控制指南1. 概述2. 有注解时参数接收方式对比3. 无注解时接收参数默认位置

SpringBoot基于配置实现短信服务策略的动态切换

《SpringBoot基于配置实现短信服务策略的动态切换》这篇文章主要为大家详细介绍了SpringBoot在接入多个短信服务商(如阿里云、腾讯云、华为云)后,如何根据配置或环境切换使用不同的服务商,需... 目录目标功能示例配置(application.yml)配置类绑定短信发送策略接口示例:阿里云 & 腾

Python ZIP文件操作技巧详解

《PythonZIP文件操作技巧详解》在数据处理和系统开发中,ZIP文件操作是开发者必须掌握的核心技能,Python标准库提供的zipfile模块以简洁的API和跨平台特性,成为处理ZIP文件的首选... 目录一、ZIP文件操作基础三板斧1.1 创建压缩包1.2 解压操作1.3 文件遍历与信息获取二、进阶技