首页 >> 大全

JVM(二).垃圾回收算法/策略内存分配

2023-09-20 大全 24 作者:考证青年

JVM(二).垃圾回收算法/策略&内存分配 1.概述

内存释放动态化:那些内存需要回收;什么时候回收;如何回收;

2.回收那些对象

垃圾回收的是不需要被使用的对象,就是可以被回收的,如何确定?

2.1 引用计数

在对象中,添加引用计数,一个地方引用+1,引用失效-1,如何时刻计数器是0 的时候就是可以回收对象了;

明显的缺点:循环引用;(a 引用b ,b 引用a,但是a,b 都没有其他引用了,这个时候是应该被回收了)

2.2 可达性分析

主流语言都在使用的,通过一系列称为 GC Roots 的节点作为其实节点集,来搜索引用链 Chain,如果一个对象没有连接到引用链,或者叫这个对象不可达,这个对象可以被回收了;

在Java体系里面 固定的 GC Roots 有以下几种

2.3 引用的级别

级别的作用就是:当内存够时,我们可以都保留,内存比较紧张的时候,就可以根据引用的级别回收固定级别的这些对象;

2.4 回收/继续存活

被可达性分析算法判定后为不可达对象后,也不是马上必须去回收,至少会有两次标记的过程:

引用链不可达是否需要执行() ,如果没有重写这个方法或者这个方法已经被调用(一个对象只会调用一次),就不会再执行这个方法;如果要执行,放入F-Queue对列,该虚拟机低优先级线程执行对列对象的 (),如果在方法里面重写建立连接,就可以避免回收,但是也有可能等不到执行就会被GC了

不建议使用!!!!

2.5 回收方法区

虚拟机规范中可以不要求实现方法区的内存回收,也有不能回收方法区的垃圾回收器(JDK11 的ZGC),回收性价比低,回收条件复杂;

回收具体有两大类:废物的常量和不在使用的类型;

第二个实现比较复杂 需要做一下判断 :

参数控制: 是否方法区 GC - ,加载和卸载信息 -:class,-XX:+;-XX:+

在使用反射,动态代理,CGLib一些字节码框架,动态生成JSP,OGSi 自定义类加载器 需要虚拟机具备类型卸载功能,来保证方法区可用;

3.垃圾回收算法 3.1 分代收集理论

1.弱分代假说:大部分对象是短暂的

2.强分代假说:多次垃圾回收后还存在就越难以消亡;

垃圾回收器回收对象的时候根据对象的年龄划分到不同的区域;也就是将上面说的短暂对象放在一起和多次GC还存在的对象放在一起;提示回收效率;针对不同的区域,又有好几个回收类型 Minor GC , Major GC, Full GC ,在进而对不同类型的 GC 有了不同的算法 标记复制 标记清楚 标记整理等回收算法;

3.跨代引用假说:占比较少,垃圾回收的年代不是孤立的

年轻代的回收需要判断是否被老年代引用, 需要把老年代加入GC Roots 但是开销巨大 ,而且就算是扫描了 年轻代的引用也会由于老年代的引用而进入老年代,为每一个对象存储跨代引用也比较浪费;所以在新生代创建一个 Set 数据结构用于划分老年代内存块,记录年轻代关联老年代的区域,在 Minor GC 的时候,把块内对象加入GC Roots 就可以了;

整堆收集 Full GC : 整个Java堆和方法区的内存回收; 3.2 标记-清除算法

Mark-Sweep 算法:两个阶段,标记要回收的对象,统一回收标记的算法;也可以反着来,标记或者的对象,清除没有被标记的对象;

比较基础的垃圾回收算法,后面的回收算法大部分是以这个为基础;该算法的主要缺点有两个:执行效率不稳定,两个阶段的执行效率随着对象数量变多而降低;第二个就是执行后内存空间碎片化的问题,无法获取连续的内存空间;

3.3 标记-复制算法

内存等量划分两块,每次只用一块,一块使用完了,或者的对象复制到另一块上面去,已使用的那块全部清除;

缺点,浪费了空间

现在的虚拟机实现 的 , 等新生代收集器就是这种内存布局;把新生代划分成Eden区域和两块 ;比例是8:1:1;

Minor GC 的时候把Eden 和 存活的对象复制到一块保留的 上面,清除Eden 和 ;如果保留的 内存不够保存存活的区域,就需要老年代担保

3.4 标记-整理算法

Mark- :标记复制对于存活率较高的区域清除效率相对就比较低下,而且还需要浪费空间和空间担保;如果是内存全部存活的老年代那种回收 对象100%存活。

算法实现:标记过程 和 标记-清除 一样,但是后面是让存活对象向内存一边移动,然后直接清除以外的内存;

如何移动对象,特别是在老年代都是在使用中的对象,对象在内存区域内的移动是比较重的操作,虚拟机会停止用户程序的执行,成为 STD stop the world

为什么要移动对象,是为了保证内存空间的连续性,提示虚拟机吞吐量;要是移动对象,停顿时间会更短,甚至不停顿;

关注吞吐量的实现

关注低延迟的实现 使用标记-清楚实现 CMS

4. 的算法实现细节 4.1根节点枚举

收集器的根节点枚举是需要暂停用户线程的,不能在节点枚举过程中出现因为用户线程发送变动,,保证分析结果的可靠性,会有STD stop the world,但是可达性分析算法可以和用户线程一起执行;

在 的实现方案里面,是有 数据结构来存储执行上下文和全局引用;

4.2 安全点

有了 可以快速完成 GC Roots 根节点枚举,但是很多代码指令会影响到 的关系,如果每一个指令都去关联一下 ,难免加大运行成本和存储成本;只是在特定的时候记录到 ,这些位置被称为安全点 ,每个指令执行都很短暂,一般选择‘长时间指令’ 比如方法调用,循环跳转,异常跳转,这些才会有安全点;

如何保证程序运行到代码附加的安全点来停顿,有两种实现方案:

抢先式中断, ,不需要线程的执行代码主动配合,GC 时,全部停止,然后把还没有到安全点的线程恢复执行,知道最近的安全点,现在很少使用了主动式中断, ,垃圾回收需要停止线程的时候,不需要对线程操作,设置一个标志位,用户线程在执行的时候(轮询的时间点:安全点+ 创建对象+ 堆内存分配内存)去轮询这个标志位,发现中断标志位就在最近的安全点上面主动挂起; 轮训指定 test 4.3 安全区域

Safe 安全点事正在执行的线程响应线程中断指令,但是用户线程处于Sleep / 状态 这个时候就无法主动响应中断了,这个时候就引入了安全区域;线程在执行到安全区域时候,垃圾回收器不会管理这些进入了安全区域的线程,等这些线程恢复的时候,如果还没有完成根节点枚举,就保持运行,一直在安全区域运行,直到枚举完成,可以离开安全区域;

4.4 Set

前面说了 Set 是记录跨代引的对象;避免全量扫描老年代;本小节主要是介绍 Set 的实现方式;若不考虑性能的话,最简单的实现就是非收集区域中所有含跨代引用对象的数组,这样也是新能比较低下的;

有三种记录方式

Card Table最简单的实现就是字节数组(不用bit 是因为现在计算机硬件指令最小都是byte),而也是这样实现的

CARD_TABLE[this addredd >> 9 ] = 0

数组内部一个对象标识者内存区域一块内存(卡页 Card Page ,大小一般是2^n 幂的字节数 上面可以看到是 9 次方 512 字节),

比如其实地址是 下面就是映射关系 , 如果 Card Page 记录的是1 就是标志着对应的内存区域是Dirty 是有跨代引用的,加入 GC Roots

4.5 写屏障

卡表元素如何维护: 何时变脏:其他区域引用了本区域,时间点就是引用对象赋值的那一刻;如何变脏:如何在赋值的时候去维护卡表;

在的实现里面是通过写屏障 Write 实现的,其处理模型可以看做是对引用对象赋值时候的AOP 切面;一个是Pre-Write 一个是Post-Write 。一般是在对象赋值后使用写后屏障更新卡表;

对于高并发下面的并发修改,JDK 后新增一个参数 -XX:+ 来判断卡表是否变成脏了,如果没有变脏才更新卡表;

4.6 并发的可达性分析

主流编程语言基本都是通过可达性分析来判断对象是否存活,算法理论上需要全过程都基于一致性的快照中去分析,意味着要停止所有用户线程;上面介绍过 来记录的根节点开始便利查找对象图,这个步骤的时间是和堆的内存大小成正比的,堆越大,就需要更多时间去标记;

如何保障一致性快照。三色标记来辅助理解

如果在回收期间一切用户线程停止,扫描就不会有任何的问题,但是如果有用户线程参与的话,一种是把要回收的变成不回收的,这个没什么问题,最多下次再回收,如果把本来存活的对象标记为要回收,就会出现问题了;下面描述此过程;

正常情况:用户线程不干预

1.引用是有方向的,只有被黑色引用才能存活;(只有根节点里面引用的对象才能活,对象引用更节点对象,不代表是可以存活的对象)

2.扫描过程,灰色是正在扫描

3.正常完成,黑色存活,白色回收 ,非黑即白

非正常情况:用户线程干预

1.扫描时,用户线程干预,切断引用(红色),本来灰色的引用指向了已经扫描过的黑色,黑色不会二次扫描了;

2.扫描时,用户线程干预,切断的引用是一段引用链:导致两个/多个对象丢失(红色)

问题的来源:原本是黑色的由于被并发干预变成了白色;下面两个条件同时满足的时候会导致这个问题

插入了一个或者黑色对象到白色对象的引用删除了灰色对象到白色对象的引用

要解决这个问题,破坏其中一个条件就可以=> 两种解决方案:

增量更新 ,当黑色插入时,记录黑色节点,扫描结束后,重写扫描这些黑色节点;可以简单的理解为,一旦黑色插入白色,就把黑色转变成黑色;(CMS 使用该方案)

原始快照 At the SATB: 灰色节点要删除的时候,保存灰色节点到删除节点记录,扫描结束之后,灰色节点作为根节点,重写扫描;(G1, 使用该方案)

5.经典垃圾回收器

下图7种作用于不同内存区域位置的垃圾回收器,连线表示可以搭配使用;

5.1

垃圾回收算法java_

JDK1.3之前的新生代唯一的垃圾回收器,单线程,运行时停止所有用户线程 ; 会发生STD 体验比较差;但是也有优点,适合内存资源有限,内存消耗较小,单线程情况下没有线程交互开销;

使用场景:客户端模式;

5.2

回收器是 回收器的多线程并行版本,代码也复用很多

JDK9 之前官方推荐使用的是 + CMS , 搭配很单一 ,JDK9之后还取消了 + Old , + CMS; 直接并入CMS

单线程环境下效果比 还要差,只有在核心比较多的情况下,才能体现其效率;默认开启的线程是CPU 核心数;参数-XX: 限制线程个数

5.3

新生代,标记-复制算法,并行 垃圾回收器;

目标:达到一个可控制的吞吐量;表面特性类似于

吞吐量  =  用户代码时间/(用户代码时间+GC 时间)

-XX: 最大垃圾回收时间;设置大于0 的毫秒值,但是也不能设置的过于小,过小会频繁的GC,减低了吞吐量;

-XX: 直接设置吞吐量大小 0~100,如果设置19 就是 1/(1+19)= 5% ;系统默认时99 ,就是1/(1+99) = 1%,允许1% GC 时间

吞吐量有限的垃圾回收器,有一个参数 -XX:+y 可以让虚拟机自适应的来分配新生代各个区域的内存大小比例(Eden,),此时只需要指定虚拟机的最大最小内存就可以了;

5.4 Old

5.5 Old

Old 是 的老年代版本,JDK6 以后才有;

下图是 Old +

5.6 CMS

CMS mark Sweep ;

目标:获取最短 回收停顿时间,关注服务响应速度,尽可能的降低系统停顿时间;基于标记-清除算法

四个步骤:

1.初始标记 CMS mark STD 标记 GC Roots 的对象 速度很快

2.并发标记 CMS mark 开始根据标记的对象开始遍历对象图,但是是和用户线程并发运行的;

3.重新标记 CMS STD 重写并发标记期间的用户线程变动导致的那一部分对象,时间比1长,但是远比2 短;

4.并发清除 CMS sweep 和用户线程一起运行,清除标记可以回收的垃圾;

时间最长的2.和4 步骤 是和用户线程并发执行的,所以总体看来,垃圾回收是和用户线程并发执行的;

优点:并发低停顿回收器;

缺点:1.资源敏感,并发占用CPU 资源,减低用户线程的吞吐量。默认启动的线程数量是 (CPU+3)/4,CPU核心数在4以上是,占用的资源少于25%;

2.无法处理浮动垃圾,重新标记阶段可以处理并发标记阶段修改的引用,但是无法处理新增的垃圾对象,并发清理更是,处理不了新增的垃圾对象;导致在本次垃圾回收阶段直到结束后,都无法处理;只能下一次处理;由于无法处理浮动垃圾,有可能出现 Mode 失败导致一次Full GC;

3.标记清理,会导致大量内存碎片;会触发Full GC

参数:-XX: 设置内存使用率 超过多少后开始GC ,JDK5 默认68% JDK6 默认92% ;生产环境根据情况权衡设置比例;

5.7G1

First 垃圾回收器技术发展史上里程碑式的成果,面向局部回收思路和基于 的内存布局形式;

面向服务器端的垃圾回收器;用来替换CMS JDK9发布:G1 取代 + Old CMS 被声明为不推荐使用

新思想:在G1 之前回收的目标,要么是老年代 Major GC,要么是新生代 Minor GC ,要么是整个Java堆 Full GC,而G1是面向整个堆内存的回收集, Set,那块内存最多垃圾数量,回收收益最大 才进行回收;这就是G1 的Mixed GC 模式;

G1: 基于 的内存布局,也遵循分代收集理论,但是堆内存的布局和其他收集器有很大区别:不在坚持固定大小和固定比例的分代内存区域划分;每一个根据需求,可以是 Eden, ,也可以是老年代空间;与此同时G1对不同角色的采用不同的策略去处理;还有一类特殊区域:,用于存放大对象。每个可以通过 -XX:设定内存大小,范围是1M~32M且是2的幂次;超过一半 的对象就是大对象,超过一个会被存放在多个连续的 ,G1 会把这多个连续的 作为老年区看待;

G1的老年代和新生代是动态的内存集合了;每次收集就是部分,避免整个Java堆垃圾回收。建立可预测的内存模型:跟踪各个区域的回收垃圾的价值大小,维护优先列表,根据用户允许的停顿时间优先处理回收价值大的,保证了有限的时间内获取最大的效率;

实现细节:

1.跨 对象的引用问题:和 Set 的实现方案差不多,但是比它复杂;实现的数据结构是一个哈希表,key 是别的的其实地址,value 是一个Set,存储的是卡表的索引号。因此堆内存的10%~20% 用于维持收集器工作;

2.GC/用户线程并发问题:G1使用SATB,回收期间,会在中划出一部分空间用于分配新的对象,G1每个创建两个TAMS (指针可以动态调节这个区域的大小),新对象的分配空间都在这两个指针上面,而这个区域也不会进行垃圾回收;但是这个区域的内存回收的速度赶不上分配的速率。就会被迫停止用户线程,进行Full GC

3.建立可靠停顿预测模型: -XX: 来设置 ,但是G1如何保证;为每一个计算出一个衰减均值 ,在垃圾回收过程中,会评估记录每个的回收耗时, Set 里面的脏卡数量;衰减均值不同于均值,最近的数据影响也是比较大;

GC步骤

1.初始标记: ,标记GC roots 关联的对象,设置TAMS ,STD 时间非常短暂

2.并发标记: 从GC roots开始对堆中对象可达性分析,时间较长,但是可以和用户线程并发执行;分析完成后,还需要重新处理SATB并发修改的对象引用;

3.最终标记:Final 对用户线程做一个短暂的暂停,处理少量的SATB

4.筛选回收:Live Date and ; 记录统计计算,回收价值排序,根据用户设置的参数,来选择多个区域回收;把回收区域的存活对象复制到空的中去,其中涉及对象引用的修改,必须停止用户线程;

用户根据设置停顿时间来在不同的应用场景中达到吞吐量和低延迟之间的平衡,但是期望停顿时间也是不能设置的太短,一般是一百多到三百多是比较适当的参数;不然回收失败还是会导致Full GC

G1的目标是取代CMS ; G1优点:G1总体是标记-整理;但是在两个之间又是标记-复制,带来的好处就是完整的内存区域,不产生内存碎片;缺点:负载高,维护的卡表内存可能会占据内存的20%;维护卡表的操作G1更加复杂;

G1更适合大内存的应用;CMS 适合小内存;两者性能的分界点在6~8G 之间;

6.低延迟垃圾回收器

回顾垃圾回收器发展史:衡量一个垃圾回收器的好坏有下面三个重要的指标

现在的硬件发展,内存越来越大,对延迟的要求越来越凸显

6.1

公司发展;官方没有支持;

目标:任何堆内存大小,垃圾回收停顿时间在10毫秒以内;

相比于 官方的ZGC ,更像是G1的下一代继承者,相似的内存布局,和处理步骤,甚至共用一部分代码; 的改进有如下:

回收步骤:

转发指针:在转移对象和用户线程并发的一种解决方案;在移动前的内存上设置保护陷阱;一旦访问到旧的内存地址就会自陷中断,进入异常处理,再有代码逻辑修改访问到新的地址。但是这样,需要操作系统支持,并且需要频繁切换到核心态,代价较大;

新方案:优点:不用设置保护陷阱;而是在原有的内存布局结构前面加上新的引用字段,正常不处于并发移动的情况下,引用指向自己;

比如多个对象引用一个对象A,原有的方式就是,只要是对象A移动的位置,所有引用到A 的对象指针地址都需要修改成新的地址;那么新的数据结构就是 对象指针地址是两部分组成,一个是 ,一个是原有的 ;在并发移动后,只需要把,只需要修改一处,就可以了;(类似于使用句柄定位对象,只是转发指针是分散在对象上面)

缺点是:每次访问对象都有一次指针转发,尽管这个开销已经被优化到一行汇编指令;

并发情况的处理,2 如果在1,3 之间的话就会出现问题, 通过 CAS 操作保证其中之一执行,另一个必须等待;

1.GC 线程复制对象副本

2.用户线程更新对象某个字段

3.GC 线程更新转发指针的引用值为新副本地址;

写屏障维护记忆矩阵,读屏障指针的转发处理;尤其是读屏障的使用,因为读的频率很高,所以必须谨慎使用,后续在JDK13 是考虑为引用访问屏障,而不去管原生数据类型的访问

6.2 ZGC

公司研发; **目标:**和上面的 一样;

在X64 平台下 (Zpage) 有大中小三种容量;

ZGC 的思路和 完全不同,设计更加复杂精巧;标志性的设计是其染色指针技术 ;以往我们要在对象上存储额外的信息,比如分代年龄,哈希码,锁等都是存储在对象头上面。正常情况下是可以流程访问,但是在并发移动情况下就会有额外的负担,又或者是不去访问对象数据就可以直接获取到对象的一些信息呢?比如是否被移动;就比如之前垃圾回收的三色标记,像 是直接在对象头上面标记的,像G1 和 就把这个数据记录在 上,这里,ZGC 是最直接的,最纯粹的; 原来是遍历对象图,现在就是遍历对象图的引用(染色指针)

染色指针:把少量信息存储在指针上的技术;64位系统,理论一次寻址可达2^64 = 16EB 的数据,但是处于需求,性能,成本AMD64 架构只支持了54位4PB 的地址总线,和 48位 256TB 的虚拟地址空间;此外操作系统还做了限制 Linux :47位 128TB进程虚拟地址 和 46位 64TB 物理地址空间, 就44位 16TB 的物理地址空间;

Linux 平台下46 位指针 前四位用于存储信息 ,剩余用于寻址 ,早就压缩了ZGC 的内存大小最大为4TB

染色指针优势:

问题:随意定义指针,操作系统是否支持,CPU 是否支持?程序代码最后都是转换成机器指令去执行,处理器不会理会指针里面多少位多少位是什么内容,只会当做是内存地址去处理;这个问题在 / SPARC 上可以直接设置忽略前几位;但是在X86-64 的平台上没有类类似的功能,这里就要说到补救措施:虚拟内存映射技术 :ZGC为了能高效、灵活地管理内存,实现了两级内存管理:虚拟内存和物理内存,并且实现了物理内存和虚拟内存的映射关系。

GC步骤

优点:不需要 Set ,写屏障,卡表;这些计算资源和空间资源都省略了;

缺点:回收周期长(不代表停顿时间 STD ) 对象的分配速度不能太快,大量新对象是浮动垃圾,只能下次回收;只能增加堆空间,获取更多喘息的时间来下次回收;

优化方案:还是需要引入分代收集,新生代专门区域,针对这个区域更频繁和更快的收集;

7.为应用选择何时的垃圾回收器

为我们应用选择适合的垃圾回收器;要考虑jvm 运行的操作系统如Win Linux ,像ZGC 在Win 上就用不了;如果机器的内存和JDK 版本较低,CMS会比较好,内存再大一点的话,就是G1 也不错;

垃圾回收算法java_

7.1 垃圾回收日志

日志级别:Trace ,Debug ,Info ,, Error,Off 默认Info 级别

日志行携带信息: 默认是: ,level,tags

以JDK 9 为分界线 参数-Xlog: : : :-统一处理系统所有日志

的种类有很多,其中就包括gc,打印GC 日志 还有其他的比如add,,cpu.jni,ihop 等等

1.默认日志打印基本信息

-Xlog:gc JDK9 之前:-XX:+

//jdk 9 之后
[0.004s][warning][gc] -XX:+PrintGC is deprecated. Will use -Xlog:gc instead.
[0.015s][info   ][gc] Using G1
Connected to the target VM, address: '127.0.0.1:64410', transport: 'socket'

2.日志打印详细信息

-X-log:gc* JDK9 之前:-XX:+

//jdk 9 之后
[0.005s][warning][gc] -XX:+PrintGCDetails is deprecated. Will use -Xlog:gc* instead.
[0.015s][info   ][gc,heap] Heap region size: 1M
[0.017s][info   ][gc     ] Using G1
[0.017s][info   ][gc,heap,coops] Heap address: 0x00000000fec00000, size: 20 MB, Compressed Oops mode: 32-bit
Connected to the target VM, address: '127.0.0.1:64611', transport: 'socket'
[20.740s][info   ][gc,start     ] GC(0) Pause Young (Normal) (G1 Evacuation Pause)
[20.740s][info   ][gc,task      ] GC(0) Using 2 workers of 10 for evacuation
[20.741s][info   ][gc,phases    ] GC(0)   Pre Evacuate Collection Set: 0.0ms
[20.741s][info   ][gc,phases    ] GC(0)   Evacuate Collection Set: 1.4ms
[20.741s][info   ][gc,phases    ] GC(0)   Post Evacuate Collection Set: 0.2ms

其实还有很多参数,自行百度搜索。。。。。

7.2 垃圾回收器参数总结

每个垃圾回收和其对应的垃圾回收参数

参数描述

模式 + Old 回收

9后不支持 + Old

+CMS+ Old;CMS失败后 Old

9之前默认 + Old

+ Old

Eden : 默认是8 代表8:1

ld

byte 超过直接老年代

每次 年龄+1 ,超过这个直接老年代

y

动态堆大小和动态进入老年代的年龄

re

允许老年代担保失败

并行GC线程数量

默认99 ,就是1/(1+99) = 1%,允许1% GC 时间;( )

最大回收时间

内存使用率超过多少开始GC

CMS后是否需要整理内存(9后废除)

CMS多少次后整理内存( 9后废除)

9后默认垃圾回收

byte Size

G1目标时间,默认200ms

新生代最小值,默认 5%

新生代最大值,默认 60%

并行GC线程数量

和用户线程一起的时候GC线程数量

默认 45% 表示ytes 堆占比

才能用

cs

何时启动GC (**默认**)、、、(**用**)、(**用**)

使用ZGC

启动NUMA 内存分配支持

8.内存分配和回收策略

Java的内存管理:自动给对象分配内存和回收对象内存;

JVM初始分配的内存由-Xms指定,默认是物理内存的1/64; 最大分配的内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,减少堆直到-Xms的最小限制。服务器一般设置-Xms、-Xmx 相等以避免GC后调整堆的大小。

JVM使用-XX:设置非堆内存初始值,默认是物理内存的1/64;由XX:设置最大非堆内存的大小,默认是物理内存的1/4。

8.1 对象优先在Eden

大部分情况是,新的对象在Eden 区中分配。当Eden 没有空间,就发起Minor GC

/*** VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8* young 10 = 8+1+1   Old :10 */public static void testAllocation() {byte[] allocation1, allocation2, allocation3, allocation4;allocation1 = new byte[2 * _1MB];allocation2 = new byte[2 * _1MB];allocation3 = new byte[2 * _1MB];allocation4 = new byte[4 * _1MB];  // 出现一次Minor GC  4M 无法进入Eden(此时6/8) 直接进入old}

[GC (Allocation Failure) [PSYoungGen: 6439K->911K(9216K)] 6439K->5015K(19456K), 0.0031737 secs] [Times: user=0.09 sys=0.02, real=0.00 secs] 
HeapPSYoungGen      total 9216K, used 7460K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)  eden space 8192K, 79% used [0x00000000ff600000,0x00000000ffc656f8,0x00000000ffe00000)  //Eden(此时6/8) 大约6Mfrom space 1024K, 88% used [0x00000000ffe00000,0x00000000ffee3ca0,0x00000000fff00000)to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)ParOldGen       total 10240K, used 4104K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)  //Old 使用4Mobject space 10240K, 40% used [0x00000000fec00000,0x00000000ff002020,0x00000000ff600000)Metaspace       used 3091K, capacity 4556K, committed 4864K, reserved 1056768Kclass space    used 324K, capacity 392K, committed 512K, reserved 1048576K

8.2大对象进入老年代

大对象设置直接进入老年代;因为在年轻代的话,可能需要很多代之后才能进入老年代,带来了很多的复制成本;

8.3 长期存活对象进入老年代

如果垃圾回收器采用分代策略管理堆内存,每次Minor GC 后年龄+1 等到15后升级到老年代;

8.4动态年龄判定

如果空间中相同年龄的对象大小大于 一半,大于等于该年龄的就直接老年代,不需要等前面设置的最大年龄

8.5 空间担保分配

Minor GC前;虚拟机检查老年代连续空间是否大于新生代所有空间;如果大于,说明Minor GC 安全;如果小于,再看参数re 是否允许担保失败,如果 true ;对比老年代最大连续空间 和 历次晋升老年代的平均内存大小,大于 可以Minor GC ,小于Full GC;

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了