JVM对象在堆内存中是否如何分配?

news2024/11/25 14:49:25

1:指针碰撞:内存规整的情况下

2:空闲列表: 内存不规整的情况下

选择那种分配方式 是有 java堆是否规整而决定的。而java堆是否规整是否对应的垃圾回收器是否带有空间压缩整理的能力决定的。

因此当使用Serial,ParNew等带有压缩整理过程的收集器时,系统采用的分配算法是指针碰撞。既简单有高效。

当使用CMS这种基于清楚算法的收集器时,理论是就只能采用复杂的空闲列表。

线程分配缓冲区如果从内存分配的角度来看,所有线程共享的java堆可以划分出多个线程私有的分配缓冲区(ThreadLocal Allocation Buffer, TLAB),以提升对象分配时的效率

3:本地线程分配缓冲:对象创建在虚拟机频繁发生,即使仅仅修改一个指指向的位置,在并发的情况下也是线程不安全的,可能正在给A对象分配内存,指针还没有来得及及时修改,对象B又同时使用了原来的指针分配内存的情况。

(1):同步锁定,JVM是采用CAS失败重试来保证操作的原子性

(2):线程隔离,把内存分配的动作按照线程划分在不同的空间中进行,即每个线程在java堆中预先分配一款小内存,成为本地线程分配缓冲。只有本地线程分配缓冲用完了以后,用新的缓冲区区时才需要同步锁定。

JVM如何判断对象可以被回收:

JVM存放着所有的对象,垃圾回收器在堆回收之前,会判断那些对象“”活着“”

引用计数法:

就是为每一个对象添加一个引用计数器,用来统计指向当前对象的引用次数,如果当前对象存在引用的更新,那么就对这个引用计数器进行增加,一旦这个引用计数器变为0,就意味着它可以被回收了。

这种方法需要额外的内存空间来存储引用计数器,但它的原理很简单,判断效率也很高。不过主流的JVM都没有采用这种方式,因为引用计数器在处理一些复杂的循环引用或者相互依赖时,可能会出现一些不再使用但是又无法回收的内存,造成内存泄露的问题。

可达性分析法:

java通过可达性算法分析判断对象是否存活,从这些节点开始,根据引用关系向下搜索,搜索过程走过的路径成为“引用链”。如果某个对象到GC Roots之间没有任何引用链相连(也成为不可达)。就证明此对象是不可能被使用的对象。就会被回收.

那些对象可以作为GC Roots?

1、虚拟机栈中的(针栈中的本地变量表)中引用的对象,列如各个线程中被调用方法堆栈中的局部变量,临时变量等

2、元空间的静态属性引用的对象,常量引用的对象。

JAVA的不同引用方式:(是通过可达性算法来说的,来判断这个GCRoot有没有引用或者指向 这个对象,而这里的引用主要分为下面4个类型)

强引用:是指代码之中普遍存在的引用赋值,即类似“Object object = new Object();”。无论任何情况下,只要强引用关系还存在,垃圾收集器就不会回收掉被引用掉的对象。

弱引用:SoftRerfence()内存充足时不回收,不充足时不回收

软引用:WeakRerfence()不管内存是否充足,只要GC一运行就会回收改信用对象

虚引用:很少用,形同虚设,他的作用就是该信用对象被GC回收时触发一个系统通知

 JVM里面垃圾回收针对的是 新生代,老年代。还有元空间。

不会针对方法的针栈进行回收,发放一旦执行了。针栈出栈,里面的局部变量就支持从内存中清理清理掉。

代码里创建的对象一般有两种:

一种短期存活的。迅速使用完就会被回收。

一种长期存活的。需要一直生存在java堆内存中。让后续程序不停的使用。

第一种短期存活的对象,通过新生代的S0和S1被垃圾回收15次后,进入老年代中。

为什么要设置老年代和新生代?(就是分代收集理论)

他是建立在两个分代假说之上。

弱分代假说:绝大多数对象都是朝生夕死的

强分代假说:熬过越多次垃圾收集过程的对象越难以消亡。

新生代和老年代有不同的特点,需要不同的垃圾回收算法。

新生的特点时,创建后很快就会被回收,所以需要一种垃圾回收算法。

老年代的特点时,创建后需要很长时间存活,所以需要另外一种垃圾回收算法。

所以需要两个区域来区分垃圾回收算法。

新生代:如果一个区域的对象都是朝生夕死的。那么就就需要把这些对象集中在一起。每次关注时如何保留少量的存活对象,而不是去标记那些大量将要被回收的对象。就能过以较低的代价回收到较大的空间。

老年代:把长期存活的对象集中在在一起。那么虚拟机就可以较低的频率来回收这个区域。这就同时兼顾了虚拟机 垃圾收集器的时间开销和内存开销。

老年代:

为什么要设置 survior1 和 survior2?

首先为什么要设置eden区。如果没有survivor区的话。Eden区每发生一次minor GC时。就会剩余存活的对象将 送入 老年代。当老年代满了以后就会major GC.从而消耗大量时间。所以此时就需要一个缓冲的地方。当Eden发生minjor GC后,将对应存活的对象送入对应的survior。而在survivor1和survivor2中拉回进行转换,只有到15次后,才会移动到对应的老年代,减少对应的major GC.

 第二个问题:为什么设置两个Survival区?因为第一次MinorGC后,Survival就会存在一些存活对象,第二次MinorGC后,Eden区的存活对象会放入Survival区,就会与Survival区之前的对象内存不连续,形成内存碎片,时间一长就会影响性能,因此需要两个Survival区,第一次MinorGC时,Eden区的存活对象转移到fromSurvival区,Eden清空,第二次MinorGC时,将Eden和fromSurvival区中存活对象转移到toSurvival,Eden和fromSurvival清空。fromSurvival和toSurvival交换角色,循环往复15次后,再传向老年代。

Eden区与survivor的比列为什么是 8:1:1

一个eden区是新生代对象出生的地方。

两个survivor区。一个用来保存上次新生代minjor GC后存活下来的对象。两外一个空着。再一次新生代发生minjor后,会将 Eden+survivor中存活的对象都复制到另外一个 survivor中。

据统计证明,90%的对象朝生夕死存活时间极短。每次gc都会回收百分只90的对象。剩下百分之10的空间预留给另外一个survivor区。

讲解常见的垃圾回收算法:

 标记-清除算法

 分为标记和清楚两个动作。首先统一标记需要回收的对象后,标记完后,然后回收掉被标记的对象。或者也可以返过来,标记存过的对象,回收未被标记的对象。标记的过程就是 属于 垃圾判定的过程。

优点:基于可达性性算法实现,实现简单,后续的收集算法都是通过这种算法实现的

缺陷:

1:执行效率不稳定,如果java堆中有大量的对象,而大部分的对象都是需要回收的。那么此时就需要大量的标记-清除的动作。标记-清除的效率会随着对象的数据递增而降低。

2:标记清除后产生大量的内存碎片,导致程序下一次运行时需要分配一个大的对象而没有足够的连续的内存空间而提前触发一次垃圾回收。

 标记-复制算法

核心思想就是“半区复制”。他是将可用内存一分为二,首先使用其中的一块内存,当时使用的一块内存用完后,将使用完内存中的存活对象复制到另外一块内存中。然后再将使用过的内存清空

 优点:实现简单,效率高。解决了标记清楚产生的内存碎片问题。

 缺点: 1:代价太多,将内存空间一份为二,浪费空间。

          2:若存活的对象太多,就会产生大量的复制操作,对应的效率降低。

 标记-整理算法

首先这里的标记过程与''标记-清除"的标记过程是一样的。但是后续动作不是直接对可回收对象进行整理,而是对存过的对象都集体移动至内存的一段。

优点:

1:没有划分区域,提高空间利用率

2:没有内存碎片

缺点:

整理的过程中,需要STW,效率变低

 分代算法

现在一般虚拟机的垃圾收集器都采用“分代”算法。

根据对象存活周期不同。将对象内存划分为“新生代”和“老年代”。java根据各个年代的不同特点采用不同的垃圾回收算法。

新生代中每次进行垃圾回收都会发现大量的对象死去。只有少量的对象存活。因此采用复制算法。只要付出少量存过对象的复制成本就可以完成收集。

老年代因为存过率极高,采用标记-清理,标记-整理 算法来进行回收

垃圾收集器:

  Serial 垃圾收集器:

 单线程工作的垃圾收集器。他先工作是必须要暂停其他所有工作的线程。知道他收集结束。就是所谓的STW.

ParNew垃圾收集器:

 他是新生代收集器。是serial收集器的多线程版本。大部分都以一样。在单CPU下,ParNew还需要切换线程,性能可能还不如 Serial

Parallel垃圾收集器

他是新生代垃圾收集器,基于复制,多线程并行的收集器(与ParNew类似)。侧重于达到一个可控的吞吐量。虚拟机允许100分钟。收集一分钟。吞吐量为99%。 吞吐量 = 运行用户代码时间/(运行用户代码时间+运行垃圾收集时间)。主要优点就是自适应调节策略。

-XX:+UseAdaptiveSizePolicy 这个参数是默认开启的。就不需要人工手动调节新生代的大小。Eden和Survivor的比列,晋升老年代大小等细节参数。虚拟机会根据当前系统运行情况收集性能监控指标信息,动态调整这些参数提供最合适的停顿时间来获取最大吞吐量,

 

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

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

相关文章

win10环境下,应用无法启动并被删除(无法完成操作,因为文件包含病毒或潜在的垃圾文件)

现象: 解决办法: 一、关闭所有自己安装的杀毒软件,如:360安全卫士,金山毒霸等 二、关闭win10本身的杀毒软件,步骤如下: 1、搜索栏输入“病毒和威胁防护” 2、进入以后,点击"病…

Pytorch迁移学习使用Resnet50进行模型训练预测猫狗二分类

目录 1.ResNet残差网络 1.1 ResNet定义 1.2 ResNet 几种网络配置 1.3 ResNet50网络结构 1.3.1 前几层卷积和池化 1.3.2 残差块:构建深度残差网络 1.3.3 ResNet主体:堆叠多个残差块 1.4 迁移学习猫狗二分类实战 1.4.1 迁移学习 1.4.2 模型训练 1.…

vue3基础+进阶(二、vue3常用组合式api基本使用)

目录 第二章、组合式API 2.1 入口:setup 2.1.1 setup选项的写法和执行时机 2.1.2 setup中写代码的特点 2.1.3 script setup语法糖 2.1.4 setup中this的指向 2.2 生成响应式数据:reactive和ref函数 2.2.1 reactive函数 2.2.2 ref函数 2.2.3 rea…

Cesium态势标绘专题-入口

本专题没有废话,只有代码,撸! 标绘主类MilitaryPlotting.ts /** 态势标绘主类* @Author: Wang jianLei* @Date: 2023-01-13 14:47:20* @Last Modified by: jianlei wang* @Last Modified time: 2023-05-31 09:55:34*/ import * as Creator from ./create/index; import Cre…

S32K324双核的核间通信使用示例

文章目录 前言修改ld文件核0的ld文件核1的ld文件 定义共享数据使用共享数据编译共享数据文件总结 前言 最近项目用S32K324开发,暂时只用了MCAL,没有Autosar上层的模块,最开始用官方给的demo工程双核可以正常跑起来,但实际开发时都…

使用nginx和ffmpeg搭建HTTP FLV流媒体服务器(摄像头RTSP视频流->RTMP->http-flv)

名词解释 RTSP (Real-Time Streaming Protocol) 是一种网络协议,用于控制实时流媒体的传输。它是一种应用层协议,通常用于在客户端和流媒体服务器之间建立和控制媒体流的传输。RTSP允许客户端向服务器发送请求,如…

数据分析工具与技术

数据分析工具与技术 数据分析技术 数据分析工具 备选方案分析 一种对已识别的可选方案进行评估的技术,用来决定选择哪种方案 或使用何种方法来执行项目工作。 其他风险参数评估 为了方便未来分析和行动,在对单个项目风险进行优先级排序时&#xff0…

GO内存模型(同步机制)

文章目录 概念1. 先行发生 编译器重排同步机制init函数协程的创建channelsync 包1. sync.mutex2. sync.rwmutex3. sync.once atomic 参考文献 概念 1. 先行发生 The happens before relation is defined as the transitive closure of the union of the sequenced before and …

超详细-Vivado配置Sublime+Sublime实现Verilog语法实时检查

目录 一、前言 二、准备工作 三、Vivado配置Sublime 3.1 Vivado配置Sublime 3.2 环境变量添加 3.3 环境变量验证 3.4 Vivado设置 3.5 配置验证 3.6 解决Vivado配置失败问题 四、Sublime配置 4.1 Sublime安装Package Control 4.2 Sublime安装Verilog插件 4.3 安装语…

centos7中MySQL备份还原策略

目录 一、直接拷贝数据库文件 1.1在shangke主机上停止服务并且打包压缩数据库文件 1.2 在shangke主机上把数据库文件传输到localhost主机上(ip为192.168.33.157) 1.3在localhost主机上停止服务,解压数据库文件 1.4 在localhost主机上开启服务 1.5 测试 二、m…

利用@Excel实现复杂表头导入

EasyPoi导入 <a-upload name"file" :showUploadList"false" :multiple"false" :headers"tokenHeader" :action"importExcelUrl"change"handleImportExcel"><a-button type"primary" icon&quo…

【软件测试】如何选择回归用例

目录 如何在原始用例集中挑选测试用例 具体实践 总结 本文讨论一下在回归测试活动中&#xff0c;如何选择测试用例集。 回归测试用例集包括基本测试用例集&#xff08;原始用例&#xff09;迭代新增测试用例集&#xff08;修复故障引入的用例和新增功能引入的用例集&#xf…

洛必达法则和分部积分的应用之计算数学期望EX--概率论浙大版填坑记

如下图所示&#xff0c;概率论与数理统计浙大第四版有如下例题&#xff1a; 简单说就是&#xff1a;已知两个相互独立工作电子装置寿命的概率密度函数&#xff0c;将二者串联成整机&#xff0c;求整机寿命的数学期望。 这个题目解答中的微积分部分可谓是相当的坑爹&#xff0c;…

【1++的C++初阶】之适配器

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的C初阶】 文章目录 一&#xff0c;什么是适配器二&#xff0c;栈与队列模拟实现三&#xff0c;优先级队列四&#xff0c;reverse_iterator 一&#xff0c;什么是适配器 适配器作为STL的六大组…

【高阶数据结构】跳表

文章目录 一、什么是跳表二、跳表的效率如何保证&#xff1f;三、skiplist的实现四、skiplist跟平衡搜索树和哈希表的对比 一、什么是跳表 skiplist本质上也是一种查找结构&#xff0c;用于解决算法中的查找问题&#xff0c;跟平衡搜索树和哈希表的价值是 一样的&#xff0c;可…

Windows环境Docker安装

目录 安装Docker Desktop的步骤 Docker Desktop 更新WSL WSL 的手动安装步骤 Windows PowerShell 拉取&#xff08;Pull&#xff09;镜像 查看已下载的镜像 输出"Hello Docker!" Docker Desktop是Docker官方提供的用于Windows的图形化桌面应用程序&#xff0c…

区间预测 | MATLAB实现QRBiLSTM双向长短期记忆神经网络分位数回归多输入单输出区间预测

区间预测 | MATLAB实现QRBiLSTM双向长短期记忆神经网络分位数回归多输入单输出区间预测 目录 区间预测 | MATLAB实现QRBiLSTM双向长短期记忆神经网络分位数回归多输入单输出区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 区间预测 | MATLAB实现QRBiLSTM…

odoo16 用好计量单位中的激活功能

odoo16 用好计量单位中的激活功能 根据国内常用&#xff0c;把不常用的单位去除&#xff0c;删除不了&#xff0c;提示已用&#xff0c;其实不用删除&#xff0c;每个单位后有个激活功能&#xff0c;选一下就可以了&#xff0c;显示成整洁的界面了 第一次用时&#xff0c;小伙伴…

解决spring cloud 中使用spring security全局异常处理器失效

写auth认证模块实现忘记密码与注册功能时&#xff0c;用异常抛出&#xff0c;全局异常处理器无法捕获。 无法进行异常捕捉 解决方案&#xff1a;使用WebSecurityConfigurerAdapter.configure中http实现自定义异常&#xff1a; EnableWebSecurity EnableGlobalMethodSecurity(…

87、springcloud核心组件及其作用

spring Eureka: 服务注册与发现 注册:&#xff1a;每个服务都向Eureka登记自己提供服务的元数据&#xff0c;包括服务的ip地址、端口号、版本号、通信协议等 eureka将各个服务维护在了一个服务清单中 (双层Map&#xff0c;第一层key是服务名&#xff0c;第二层key是实例名&…