为什么会有新生代?

如果不分代,所有对象全部在一个区域,每次GC都需要对全堆进行扫描,存在效率问题。分代后,可分别控制回收频率,并采用不同的回收算法,确保GC性能全局最优。

为什么新生代会采用复制算法?

新生代的对象朝生夕死,大约90%的新建对象可以被很快回收, 复制算法成本低,同时还能保证空间没有碎片。虽然标记整理算法也可以保证没有碎片,但是由于新生代要清理的对象数量很大,将存活的对象整理到待清理对象之前,需要大量的移动操作,时间复杂度比复制算法高。

为什么新生代需要两个Survivor区?

为了节省空间考虑,如果采用传统的复制算法,只有一个Survivor区,则Survivor区大小需要等于Eden区大小,此时空间消耗是8 * 2,而两块Survivor可以保持新对象始终在Eden区创建,存活对象在Survivor之间转移即可,空间消耗是8+1+1,明显后者的空间利用率更高。

新生代的实际可用空间是多少?

YGC后,总有一块Survivor区是空闲的,因此新生代的可用内存空间是90%。在YGC的log中或者通过 jmap -heap pid 命令查看新生代的空间时,如果发现capacity只有90%,不要觉得奇怪。

Eden区是如何加速内存分配的?

HotSpot虚拟机使用了两种技术来加快内存分配。分别是bump-the-pointer和TLAB(Thread Local Allocation Buffers)。

由于Eden区是连续的,因此bump-the-pointer在对象创建时,只需要检查最后一个对象后面是否有足够的内存即可,从而加快内存分配速度。

TLAB技术是对于多线程而言的,在Eden中为每个线程分配一块区域,减少内存分配时的锁冲突,加快内存分配速度,提升吞吐量。

2. 新生代的4种回收器

SerialGC(串行回收器),最古老的一种,单线程执行,适合单CPU场景。

ParNew(并行回收器),将串行回收器多线程化,适合多CPU场景,需要搭配老年代CMS回收器一起使用。

ParallelGC(并行回收器),和ParNew不同点在于它关注吞吐量,可设置期望的停顿时间,它在工作时会自动调整堆大小和其他参数。

G1(Garage-First回收器),JDK 9及以后版本的默认回收器,兼顾新生代和老年代,将堆拆成一系列Region,不要求内存块连续,新生代仍然是并行收集。

上述回收器均采用复制算法,都是独占式的,执行期间都会Stop The World.

3. YGC的触发时机

当Eden区空间不足时,就会触发YGC。结合新生代对象的内存分配看下详细过程:

1、新对象会先尝试在栈上分配,如果不行则尝试在TLAB分配,否则再看是否满足大对象条件要在老年代分配,最后才考虑在Eden区申请空间。

2、如果Eden区没有合适的空间,则触发YGC。

3、YGC时,对Eden区和From Survivor区的存活对象进行处理,如果满足动态年龄判断的条件或者To Survivor区空间不够则直接进入老年代, 如果老年代空间也不够了,则会发生promotion failed,触发老年代的回收。否则将存活对象复制到To Survivor区。

4、此时Eden区和From Survivor区的剩余对象均为垃圾对象,可直接抹掉回收。

此外,老年代如果采用的是CMS回收器,为了减少CMS Remark阶段的耗时,也有可能会触发一次YGC,这里不作展开。

4. YGC的执行过程

YGC采用的复制算法,主要分成以下两个步骤:

1、查找GC Roots,将其引用的对象拷贝到S1区

2、递归遍历第1步的对象,拷贝其引用的对象到S1区或者晋升到Old区

上述整个过程都是需要暂停业务线程的(STW),不过ParNew等新生代回收器可以多线程并行执行,提高处理效率。

YGC通过可达性分析算法,从GC Root(可达对象的起点)开始向下搜索,标记出当前存活的对象,那么剩下未被标记的对象就是需要回收的对象。

可作为YGC时GC Root的对象包括以下几种:

1、虚拟机栈中引用的对象

2、方法区中静态属性、常量引用的对象

3、 本地方法栈中引用的对象

4、 被Synchronized锁持有的对象

5、 记录当前被加载类的SystemDictionary

6、 记录字符串常量引用的StringTable

7、 存在跨代引用的对象

8、 和GC Root处于同一CardTable的对象

其中1-3是大家容易想到的,而4-8很容易被忽视,却极有可能是分析YGC问题时的线索入口。

另外需要注意的是,针对下图中跨代引用的情况,老年代的对象A也必须作为GC Root的一部分,但是如果每次YGC时都去扫描老年代,肯定存在效率问题。在HotSpotJVM,引入卡表(Card Table)来对跨代引用的标记进行加速。

Card Table,简单理解 是一种空间换时间的思路,因为存在跨代引用的对象大概占比不到1%,因此可将堆空间划分成大小为512字节的卡页,如果卡页中有一个对象存在跨代引用,则可以用1个字节来标识该卡页是dirty状态,卡页状态进一步通过写屏障技术进行维护。

遍历完GC Roots后,便能够找出第一批存活的对象,然后将其拷贝到S1区。接下来,就是一个递归查找和拷贝存活对象的过程。

S1区为了方便维护内存区域,引入了两个指针变量:_saved_mark_word和_top,其中_saved_mark_word表示当前遍历对象的位置,_top表示当前可分配内存的位置,很显然,_saved_mark_word到_top之间的对象都是已拷贝但未扫描的对象。

如上图所示,每次扫描完一个对象,_saved_mark_word会往前移动,期间如果有新对象也会拷贝到S1区,_top也会往前移动,直到_saved_mark_word追上_top,说明S1区所有对象都已经遍历完成。

有一个细节点需要注意的是:拷贝对象的目标空间不一定是S1区,也可能是老年代。如果一个对象的年龄(经历的YGC次数)满足动态年龄判定条件便直接晋升到老年代中。对象的年龄保存在Java对象头的mark word数据结构中(如果大家对Java并发锁熟悉,肯定了解这个数据结构,不熟悉的建议查阅资料了解下,这里不做展开

GC相关问题的更多相关文章

  1. Jmeter性能测试-GC相关

    1.GC相关 HotSpot虚拟机将其物理上划分为两个–新生代(young generation)和老年代(old generation).新生代(Young generation): 绝大多数最新被 ...

  2. java栈内存堆内存和GC相关

    java栈内存堆内存 Java把内存分成两种,一种叫做栈内存,一种叫做堆内存,有着不同的作用.栈内存用来存储局部变量和方法调用.栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属 ...

  3. elastic的gc相关

    https://www.jianshu.com/p/1f450826f62e   gc原理介绍 相关优化 https://zhaoyanblog.com/archives/319.html 问题 ht ...

  4. 三.GC相关之三分钟认识GC算法

    GC算法慢慢演化,进化到了现在的分代GC.其进化过程 标记-清除算法 –> 标记-复制算法 –> 标记-整理算法 –> 分代算法. 在介绍算法之前,我们知道Java是动态加载.其特点 ...

  5. 二.GC相关之Java内存模型

    根据上节描述的问题,我们知道其最终原因是GC导致的.本节我们就先详细探讨下与GC息息相关的Java内存模型. 名词解释:变量,理解为java的基本类型.对象,理解为java new出来的实例. Jav ...

  6. Java GC相关知识

    Java堆的分类 分为两类:YoungGen和OldGen.其中,YoungGen分为三部分:eden,from survivor和to survivor,比例默认是:8:1:1 PermGen不属于 ...

  7. elasticsearch 的内存JVM和GC相关问题

    JVM对ElasticSearch集群的稳定性有很大的影响. Java是一个垃圾收集语言,意思是这个程序不会手动管理分配和释放内存.程序员只需要编写代码,jvm管理根据需要管理分配内存的处理,然后在不 ...

  8. 内存泄露,GC相关

    内存泄露就是对象不在GC的掌控之内 下面对象会发生内存泄露现象: 1.没有引用的对象 2.虚,软,弱 引用对象 GC引用的对象指的是 1.JavaStack中引用的对象 2.方法区中静态引用指向的对象 ...

  9. JVM GC 相关

    http://blog.csdn.net/cutesource/article/details/5904501 http://www.cnblogs.com/dingyingsi/p/3760447. ...

  10. GC相关的面试题

    问题:Object的finaliz()方法 的作用是否与C++的析构函数作用相同? --->不同的 1.C++的析构函数调用确定,就是对象离开作用域之后就马上被删除.而java Object的f ...

随机推荐

  1. Webflux(史上最全)

    文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...

  2. 再有人问你HashMap,把这篇文章甩给他

    搞定HashMap 作为一个Java从业者,面试的时候肯定会被问到过HashMap,因为对于HashMap来说,可以说是Java==集合中的精髓==了,如果你觉得自己对它掌握的还不够好,我想今天这篇文 ...

  3. Mybatis数据连接池的配置---增删改查(以及遇见的问题)

    1.首先创建项目和各个文件,如图所示: 2.配置相关数据库连接 在jdbc.properties中加入 1 db.driver=com.mysql.jdbc.Driver 2 db.url=jdbc: ...

  4. 玩转STM32MP157-开发环境搭建

    (一)STM32MP 1.什么是 STM32MPU STM32MPU是 ST 推出的 Cortex-A7 + Cortex-M4 多核异构处理器 STM32MPU151 是单核 A7+M4,.STM3 ...

  5. Cygwin-OpenSSH配置手册及常见问题解决

    右键管理员方式运行Cygwin-setup-x86_64.exe 选择Install from Local Ddirectory 选择安装路径(默认下一步) 选择依赖库路径 依次配置一下选项 接下来安 ...

  6. 面试题二:JVM

    JVM垃圾回收的时候如何确定垃圾? 有2种方式: 引用计数 每个对象都有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收: 缺点:无法解决对象循环引用的问题: 可达性分 ...

  7. 1.3.2、通过Cookie匹配

    server: port: 8080 spring: application: name: gateway cloud: gateway: routes: - id: guo-system4 uri: ...

  8. Python 绘制词云

    文本内容:data(包含很多条文本) 1.分词: import jieba data_cut = data.apply(jieba.lcut) 2.去除停用词: stoplist.txt:链接:htt ...

  9. 掌握了这几个Linux命令可以让你工作效率提高一倍

    01 top命令 第一个命令就是top,这个命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用情况,有点类似Windows下的任务管理器. 最上面每一行都表示一种性能数据: t ...

  10. Oracle如何以逗号分隔的字符串拆分为多行数据

    近期在工作中遇到某表某字段是可扩展数据内容,信息以逗号分隔生成的,现需求要根据此字段数据在其它表查询相关的内容展现出来,第一想法是切割数据,以逗号作为切割符,以下为总结的实现方法,以供大家参考.指教. ...