面试官问为什么新生代不用标记清除算法
杭州某写字楼,安琪拉穿着新买的19.9的皮鞋走进玻璃隔间办公室,准备迎接一场新的表演。
面试官 :看你简历上有些熟悉JVM,是吧?
安琪拉:是的
面试官 :那你跟我讲讲堆内存的分区。
安琪拉:[心想]:这很easy嘛,来,算是回顾一下JVM的基础知识。
我们知道堆分为新生代和老年代,新生代就是我们说的Yong Generation,老年代是 Old Generation。
面试官 :然后呢?
安琪拉:然后什么?
面试官 :讲完啦?下面没有啦?新生代呢?
安琪拉:你想听你可以跟我说嘛,你不说我怎么知道你想听。
新生代又分为Eden区和Survivor区,Survivor由From区域和To区域组成,完整的内存结构,我给你画一下,别抽了,笔递给我一下,我画一下,如下图所示。
面试官 :哦,图可以,那为什么堆要分新生代和老年代呢?
安琪拉:当然是为了更有效的管理内存。
面试官 :怎么说?
安琪拉:假设一下,如果不分新老代,内存就一整块,垃圾收集器每次都要把那些长期存在的对象,和生命周期很短的对象放在一起回收,一般长生命周期的对象可能跟应用生命周期一致,你基本回收不掉的,比如Spring 框架里面的Bean管理相关的对象(ApplicationContext),整个应用运行期间都存在,这种一般经过几次回收最后都放在老年代,但是如果不区分新老代,每次都一起回收,性能消耗很大。
区分新老代之后,老年代放长期存活的对象,新生代就放生命周期短的对象,老年代对象很稳定,新生代回收不影响老年代,回收效率能大大提高。
面试官 :那为什么新生代还要分Eden、From、To区域呢?
安琪拉:[开始慢慢有点意思了]
首先大部分对象生命周期是很短的,如果新生代不分多个区域,新生代可能会有二种回收方案
第一种可能:每次回收都在新生代整块内存上进行,完整的垃圾回收过程分三步:
需要先找到需要清理的对象标记;
清理这些被标记的对象;
移动剩下的对象,对达到老年代晋升年龄的对象移动到老年代。
对象被回收掉后会产生很多内存碎片(被回收的对象很多),如果要解决内存碎片,需要移动剩下的对象(标记整理算法),整个回收流程效率很低。
第二种可能:如果没有Survivor区(From + To),Minor GC(新生代回收)过程中,存活的对象直接被送到老年代,这样的话老年代很快被填满,触发Major GC(因为Major GC一般伴随着Minor GC,也可以看做触发了Full GC),Full GC频繁会影响程序的执行和响应速度。
新生代的回收叫Minor GC, 老年代的回收叫Major GC。
面试官 :为什么要设置两个Survivor区呢?From 和 To
安琪拉:我们来看一下, 如果只有一个Survivor区,新生代内存的回收流程。
我按照上面这张图画的讲,第一次Eden区域满了,内存回收很简单,直接把Eden区域存活对象放到Suvivor区域;
第二次内存回收,需要回收二个地方,Eden区域和Survivor区域。
因为Survivor区域也会存活的对象需要被回收,对Survivor区要采用标记整理垃圾收集算法,(先标记需要清理的对象,然后回收,然后把剩下的存活对象放到一起);
Eden区域采用复制算法,把Eden区域存放的对象复制到Survivor区域,然后把整个Eden区清除。
看到网上有些文章说这里设置二个Survivor区域的原因是为了避免内存碎片,因为他假设第二次(以及后续)的回收,内存回收是先回收Eden区域,然后是Survivor区域,这样当然会有内存碎片,但是如果真是只有一个Survivor区域,垃圾回收设计者肯定是先回收Survivor区域,再回收Eden区域,等Survivor区回收整理好,再把Eden区存放对象搬到Survivor区,这样存活地址是连续的,没有内存碎片。所以真正的原因还是我下面说的效率问题。
面试官 :这样有什么问题呢?
安琪拉:这样做有几个问题:
经过几次回收之后,Survivor区域满了之后怎么办?直接搬到老年代?那老年代很快就爆炸了。搬到Eden区?那内存碎片产生了,可能Survivor区和Eden区回收完之后,还需要再整理一下内存去掉内存碎片,性能消耗也是很大的。
一般标记整理算法的性能消耗是比复制算法消耗要大的,尤其是在新生代98%的对象都是“朝生夕死”的,标记清楚的是98%的对象,剩下就2%对象,要整理内存,不然直接把这2%对象放到另一个地方,把整块内存清除,Eden整块内存清除效率很高的。
所以归根结底,二个Survivor区还是为了性能考虑,标记复制算法效率比标记整理效率高。
面试官 :那你跟我详细讲讲标记新生代除了Eden,另外采用二个Survivor区的标记复制算法。
安琪拉:新生代中的对象 98% 是“ 朝生夕死” 的, 所以并不需要按照 1: 1 的比例来划分Eden和Survivor的空间, 而是将新生代分为较大的一块Eden空间和两块较小的Survivor 空间,每次只使用 Eden 和 其中一块Survivor[0](From区域),留出Survivor[1](To区域)用来实现标记复制。
当回收时, 将 Eden 和 Survivor[0] 中还存活着的对象一次性地复制到另外一块 Survivor[1] (To)空间上, 最后清理掉 Eden 和 刚才用过的 Survivor 空间。
另外说明一点:From区域和To区域在每次Minor GC之后都会互转,From区域变成To区域,To区域变成From区域,这只是逻辑标识
HotSpot 虚拟机默认 将Eden 和 Survivor 的大小比例是 8: 1(CMS不适用), 也就是每次新生代中可用内存空间为整个新生代容量的 90%( 80%+ 10%),只有10%的内存会被“ 浪费”(一直有10%的内存(Survivor To区)不存东西)。
标记复制算法流程:
Eden区域+Survivor From区满,进行存活对象标记,标记完,把存活对象复制到Survivor To区域;
Survivor To区域变成From区域(一个逻辑标识),From区域变成To区域;
内存分配,继续步骤1,复制过程中有达到老年代晋升年龄(默认值15),移动到老年代。
面试官:刚才说了这么多,是不是来之前背题了?
安琪拉:【心想】回答不出来你说我对技术没追求,回答出来了你说我背题,WTF。。
耐心对面试官解释:怎么可能,我只不过是来之前把安琪拉的博客公众号上的文章都看了一遍,嘿嘿。
面试官:在哪看,你分享给我。
面试官:诶诶,还有老年代内存回收策略呢?还有标记整理算法呢?另外讲讲几种常见的垃圾回收器,CMS和G1。
安琪拉:不想讲了,累了,要不放在二面的时候讲吧。
面试官:没事,二面面试官还是我,你直接讲吧。
安琪拉:真不想讲了。
面试官:那今天先到这吧,回去等通知,您出了这个门左拐。
文章来源于读者的提问。
面试官问为什么新生代不用标记清除算法相关推荐
- 【阿里二面】面试官问为什么新生代不用标记清除算法
杭州某写字楼,安琪拉穿着新买的19.9的皮鞋走进玻璃隔间办公室,准备迎接一场新的表演. 面试官 :看你简历上有些熟悉JVM,是吧? 安琪拉:是的 面试官 :那你跟我讲讲堆内存的分区. 安琪拉:[心想] ...
- 看完这篇,我再也不怕面试官问垃圾收集了
看完这篇,我再也不怕面试官问垃圾收集了 说在前面:本文的篇幅较长,看本文的时候最好先去上个厕所,先准备好一杯枸杞茶,慢慢品,本文将会讲解三种垃圾收集算法:标记-清除.复制.标记-整理算法,以及各种成熟 ...
- 大叔手记(10):别再让面试官问你单例
大叔手记(10):别再让面试官问你单例(暨6种实现方式让你堵住面试官的嘴) ... 2012-2-19 09:03| 发布者: benben| 查看: 283| 评论: 0 摘要: 引子经常从Recr ...
- 已经成功拿到了几个offer的我来告诉你,Android面试官问的一些问题,看完这一篇就没有拿不到的offer
前言 我是2020年毕业于中南大学的计算机学院的,大家可以叫我小吴,我嘞毕业之后在华为实习了差不多一年多,一直都从事着Android开发. 然后2021年的时候因为我自己的一些原因打算离职到外面看看, ...
- 面试官问我Java8~14的有哪些重要的新特性,我哭了~~~
大家好,我是Guide哥!这篇文章来自读者的投稿,经过了两次较大的改动,两周的完善终于完成.Java 8新特性见这里:Java8新特性最佳指南 . Guide 哥:别人家的特性都用了几年了,我 Jav ...
- 面试官问你GC怎么调优?思路是什么呀?我直接把这篇文章甩到面试官脸上
有学过JVM垃圾回收机制的小伙伴肯定了解过CG调优,当面试官问到这个问题时,相信很多小伙伴第一时间想到的就是调节几个参数,调节一下分代的大小.简单的可以用这么一句话概括,水多了加面,面多了加水.十分形 ...
- 面试官问:数据库 delete 表数据,磁盘空间还是被一直占用,为什么?
以下文章来源方志朋的博客,回复"666"获面试宝典 最近有个上位机获取下位机上报数据的项目,由于上报频率比较频繁且数据量大,导致数据增长过快,磁盘占用多. 为了节约成本,定期进行数 ...
- 面试官问:Kafka 会不会丢消息?怎么处理的?
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! Kafka存在丢消息的问题,消息丢失会发生在Broker, ...
- 当面试官问我ArrayList和LinkedList哪个更占空间时,我这么答让他眼前一亮
前言 今天介绍一下Java的两个集合类,ArrayList和LinkedList,这两个集合的知识点几乎可以说面试必问的. 对于这两个集合类,相信大家都不陌生,ArrayList可以说是日常开发中用的 ...
最新文章
- CV之detectron2:detectron2安装过程记录
- 【十大经典数据挖掘算法】Naïve Bayes
- Python学习笔记:TypeError: not all arguments converted during string formatting
- 转载:实用 FRIDA 进阶 --- objection :内存漫游、hook anywhere、抓包
- 【JZOJ3885】【长郡NOIP2014模拟10.22】搞笑的代码
- SOPC自定义外设(IP)的地址对齐
- 2019 年互联网人才招聘报告:Java 吃香,算法工程师紧缺,今日头条崛起!
- day_05、内置函数、匿名函数
- IntelliJ IDEA多屏后窗口不显示问题解决(用工具一键解决)
- 【硬币识别】基于matlab形态学硬币计数【含Matlab源码 683期】
- 单片机PWM舵机控制原理
- 考研日语线上笔记(六):完型专项篇
- MYSQL时间函数之NOW()
- 虚拟DOM和deff算法
- 千万不要用memset函数对二维数组进行初始化
- 拉线传感器的数显仪表在测量中起到多大的作用
- 基于ROS的18届中航杯比赛流程实现
- 云计算概念 IaaS PaaS SaaS
- SwiftUI iOS 完整项目之基于CoreData构建购物计划App(教程含源码App Store上线app)
- Python网络爬虫之HTTP原理
热门文章
- Fedora中安装 Shutter步骤介绍
- 如何在Ubuntu Linux上开采以太坊?
- gbdt 算法比随机森林容易_机器学习(七)——Adaboost和梯度提升树GBDT
- 对‘pthread_create’未定义的引用_深入浅出 C++ 11 右值引用
- 如何实现java虚拟机的优化_Java虚拟机JVM优化实战的过程全记录
- Codeforces Round #704 (Div. 2)(A ~ E)5题全 超高质量题解【每日亿题2 / 23】
- AcWing 734. 能量石 (01背包)+(贪心 - 领项交换)
- 幸运数字Ⅱ(树型结构构造答案,打表)难度⭐⭐
- mysql 并发 参数_Mysql并发参数调整
- 7-5 符号配对 (20 分)