作者简介:曾任职于阿里巴巴,每日优鲜等互联网公司,任技术总监,15年电商互联网经历。

最近有些读者反应:看了很多网上关于JVM的文章,但是大部分文章不够通俗易懂,看不太明白。希望笔者能写几篇关于JVM的文章,刚好我也有这方面的打算。从本文开始推出JVM系列原创文章!

GC-垃圾回收,是Java程序员长聊的话题,理解JVM垃圾回收的原理和过程,不但有助于写出高质量高性能的代码,也可以帮你在面试官面前侃侃而谈!

读完本文,对垃圾回收过程、以及回收算法在垃圾回收中的应用,将会有一个全新的认识和理解。

堆内存结构


我们以Java官方的HotSpot JVM为例,在描述GC过程前,先了解一下堆内存的结构。

JVM将堆内存分为了三部分:新生代(Young Generation),老年代(Old Generation),永久代(Permanent Generation)。其中新生代又分为三部分:伊甸园区(Eden),和两个幸存区S0和S1。

注:JDK1.8之后,Java官方的HotSpot JVM去掉了永久代,取而代之的是元数据区Metaspace。Metaspace使用的是本地内存,而不是堆内存,也就是说在默认情况下Metaspace的大小只与本地内存的大小有关。因此JDK1.8之后,就见不到java.lang.OutOfMemoryError: PermGen space这种由于永久代空间不足导致的内存溢出的问题了。

垃圾回收全过程


新创建的对象会先被分配到到Eden区。JVM刚启动时,Eden区对象数量较少,两个Survivor区S0、S1几乎是空的。

随着时间的推移,Eden区的对象越来越多。当Eden区放不下时(占用空间达到容量阈值),新生代就会发生垃圾回收,我们称之为Minor GC或者Young GC。

发生GC时,第一步会通过可达性分析算法找到可达对象。如上图,蓝色为可达对象,其他紫色为不可达对象。第二步,被标示的可达对象会被转移到S0(此时S0是From Survivor),此时存活对象年龄加1,三个对象年龄都变为1。第三步,清除Eden区所有对象。

GC后各区域对象占用情况,如上图所示。

程序继续运行,Eden区再次达到容量阈值时,会再次发生GC。这时S0(From Survivor)已经有了对象。还是同样的步骤,通过可达性分析算法找到可达对象,然后再将Eden和S0中的可达对象转移到S1(To Survivor),各存活对象年龄加1。最后将Eden和S0中的所有对象清除。

GC后S0区域被清空。如上图所示。S0和S1发生了互换,S1变成了From Survivor,S0变成了To Survivor。

注意,To Survivor区永远都为空。这实际上是垃圾回收算法-复制算法在年轻代的实际应用。把年轻代分为Eden,S0,S1三个区域,每次垃圾回收时把可达对象复制到S0或S1,然后再清除掉Eden和(S1或S0)中的所有对象。由于每次GC时,新生代的可达对象非常少(绝大部分对象要被回收掉),一般不会超过新生代总体空间的10%,所以搜寻可达对象以及复制对象的成本都会非常低。而且这种复制的方式还能避免产生堆内存碎片,提高内存利用率。很多年轻代垃圾收集器都采用复制算法,如ParNew。

在程序运行过程中,新生代GC会反复发生,长寿对象会在S0和S1之间反复交换,年龄也会越来越大,当对象达到年龄上限时,会被晋升到老年代。这个年龄上限默认是15,可以通过参数-XX:MaxTenuringThreshold设置。如下图,有些年轻代对象年龄达到了上限15,被转移到了老年代。

其他晋升方式。新生代对象晋升到老年代,除了根据年龄正常晋升外。为了提高JVM的性能,JVM设计者还考虑了其他晋升方式。

大对象直接晋升。大对象会跨过年轻代直接分配到老年代。可以通过-XX:PretenureSizeThreshold参数设置对象大小。如果参数被设置成5MB,超过5MB的大对象会直接分配到老年代。这样做的目的,是为了避免大对象在Eden区及两个Survivor区之间大量的内存复制,大对象的内存复制耗时比普通对象要高很多。

注意:PretenureSizeThreshold参数只对Serial和ParNew两种回收器有效。

动态对象年龄判定。如果在Survivor空间中相同年龄对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象会直接进入老年代,而不用等到MaxTenuringThreshold中设置的年龄上限。上图,年龄为1的对象超过了Survivor空间的一半,所以这几个对象会直接进入老年代。

实际上,上面对动态对象年龄判定的描述并不精确。上图的场景也会导致相关对象晋升到老年代。年龄为1的对象加上年龄为2的对象超过了半数,这时包括年龄为2的对象以及年龄更大的对象都会被晋升到老年代。所以上图中年龄为2和3的对象都会被晋升到老年代。

老年代垃圾回收。随着年轻代对象的不断晋升,老年代的对象变得越来越多,达到容量阈值后老年代也会发生垃圾回收,我们称之为Major GC或者Full GC,Full GC并不是全局GC,它只发生在老年代。

虽然年轻代和老年代都会发生GC,但是每次GC的时间和成本却大不相同。由于老年代空间大小一般是年轻代的几倍,再加上老年代对象存活率很高,所以整个标记过程比较慢,GC成本也非常高。我们经常说的JVM调优,主要是为了尽量减少老年代Full GC的时间和频次。

老年代垃圾回收器,很少使用复制算法,主要为了避免大量对象的内存复制带来的时间和空间上的开销,一般采用标记清除、标记整理算法,就地标记回收。例如,老年代垃圾收集器CMS就采用了标记清除算法。对于标记清除算法带来的内存碎片问题,CMS提供了两个参数做碎片整理,-XX:+UseCMSCompactAtFullCollection和-XX:CMSFullGCsBeforeCompaction。

希望本文对大家有所帮助。

特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:

长按订阅更多精彩▼如有收获,点个在看,诚挚感谢

小白搞懂了GC全过程,全靠阿里专家12张图相关推荐

  1. 一口气搞懂「文件系统」,就靠这 25 张图了

    前言 不多 BB,直接上「硬菜」. 正文 文件系统的基本组成 文件系统是操作系统中负责管理持久数据的子系统,说简单点,就是负责把用户的文件存到磁盘硬件中,因为即使计算机断电了,磁盘里的数据并不会丢失, ...

  2. 一口气搞懂「链表」,就靠这20+张图了

    顺序存储和链式存储 数组-顺序存储 数组作为一个顺序储存方式的数据结构,可是有大作为的,它的灵活使用为我们的程序设计带来了大量的便利: 但是,但是,数组最大的缺点就是我们的插入和删除时需要移动大量的元 ...

  3. 【JVM】一文搞懂常见GC算法

    文章内容 1.概述 2.如何确定垃圾对象? 3.GC算法 4.GC算法总结 5.常见的垃圾收集器 1.概述 GC目的:程序运行过程中可能会产生许多垃圾对象,持续占用内存会造成内存泄漏,最终可能导致内存 ...

  4. 一篇文章搞懂STL中的空间配置器allocator(原创,多图,易懂)

    Table of Contents 0.引入 1.标准的空间配置器allocator 2.更为高效的空间配置器alloc 2.1----对象的构造与析构 2.1.1 对象的构造:::construct ...

  5. java gc日志乱码_6000+字,30+张图。JAVA线上故障排查全套路总结。

     fredalxin|https://sourl.cn/duWZhd 线上故障主要会包括 cpu.磁盘.内存以及 网络 问题,而大多数故障可能会包含不止一个层面的问题,所以进行排查时候尽量四个方面依次 ...

  6. 12张图看懂SQL的设计思想

    前言 很多程序员视 SQL 为洪水猛兽.SQL 是一种为数不多的声明性语言,它的运行方式完全不同于我们所熟知的命令行语言.面向对象的程序语言.甚至是函数语言(尽管有些人认为 SQL 语言也是一种函数式 ...

  7. python一张图学懂_【python系统学习07】一张图看懂字典并学会操作

    一张图get字典 一张图get字典的些许知识点 如果图中知识点描述过于概括,请看下列细文: 字典是什么 js的对象 说到字典,前端同学可以理解其为:对象.因为python中的字典和js中的对象长的不能 ...

  8. 12 张图看懂 CPU 缓存一致性与 MESI 协议,真的一致吗?

    本文已收录到  GitHub · AndroidFamily,有 Android 进阶知识体系,欢迎 Star.技术和职场问题,请关注公众号 [彭旭锐] 进 Android 面试交流群. 前言 大家好 ...

  9. 世界上最诡异的12张图,看懂的人都惊呆了!

    点不见了 盯着中间的十字看,很快你会发现,闪烁的紫点变成了绿色的.更为奇妙的是,如果你不眨眼地看半分钟以上,所有紫点都消失不见,只有绿点一直在动! 握个手吧 你以为这只是一张简单的动图?NO NO,画 ...

最新文章

  1. 免费直播:1小时带你体验Python车牌识别实战
  2. hp服务器维护开关,HP服务器开机无显维修案例
  3. c++经典书籍--Effective C++
  4. 内存条ar开头的如何看大小_软网推荐:明明白白看内存
  5. [机器学习]gcForest算法理解
  6. 会话和连接的区别_websocket和ajax区别,只有这5点不同
  7. hibernate配置多数据源
  8. android外接usb摄像头demo_手机USB接口有哪些功能 手机USB接口功能介绍【详解】
  9. 剑指offer面试题58 - I. 翻转单词顺序(双指针)
  10. python基础--函数作用域
  11. web 端可交互的离线渲染器,求 star~
  12. 成为一名初级游戏策划
  13. 何謂 Raw Data ?
  14. 证监会行业分类代码对照表(2001+2012年)
  15. t-SNE可视化-Python实现
  16. 深度学习 Day 8——解决GIF生成错误以及有关GAN过程问题
  17. 基于spring boot的婚纱摄影约拍系统
  18. 用glRotatef函数转动对象
  19. 聚焦低代码SaaS云服务,让企业轻松办公!
  20. 全志XR829 WIFI和BT模块在T7 Android8.1上调试

热门文章

  1. 手把手教你 Socket 通信(TCP/IP)
  2. PyCaret-低代码ML库使用指南
  3. JavaScript初学者编程题(25)
  4. php网站怎么伪静态,php怎么实现网页伪静态
  5. EOJ Monthly 2020.7 Sponsored by TuSimple 部分题解
  6. Balkan2007]Toponyms[链式前向星建字典树+getchar()读入优化]
  7. 取名字_公司起名起名免费建筑公司取名字大全
  8. java 注解开发_Java中的注解到底是如何工作的?
  9. 计算机硬件带软件怎么入账,小企业购置计算机硬件所附带的、未单独计价的软件,通过( )科目核算。A.无形资产B.固定资产C.在 - 赏学吧...
  10. 算法竞赛知识合集 目录(博客中转站)