震惊! GC原来是这个样子.
刚学java的时候,你可能好奇,java的GC是个啥呢?
GC全称Garbage Collection/Collector(垃圾回收器),是一种虚拟机帮助程序员管理内存的方式.
打个比方.
你在C++程序员食堂吃饭,吃完了你得把盘子这些收拾干净然后送到指定地点.
但是呢,有时候你会忘掉收拾(吃完就溜~~),这个位置不就没人会坐了嘛,这就是忘记释放内存.
但是java程序员食堂就不一样了,(手动狗头),吃完了可以甩手就走.
因为有专门的阿姨帮他们收拾桌子.懒人的福利~~
垃圾收集算法
标记 - 清除算法
"标记 - 清除" 算法是最基础的算法.
首先,它会标记需要回收的对象,标记完成之后回收所有被标记的对象.
再次回到java食堂~~
举个栗子,今天梁非凡,老八,乌鸦喊你吃饭了,点了慢慢一大桌菜!饭店上菜嘛,有快有慢,吃完的盘子得撤掉来给下道菜留个空间.但是呢,不幸的是,盘子有大有小,之前小盘子的位置咋放大盘子?这可咋整呢?
复制算法
复制算法讲内存分成两个部分,而且每次只用一半,如果那一半快用完了,就把存活对象依序复制到另一块上,再把用过的那块全部清理掉.这种算法可以忽略内存碎片的问题,但是缺点也很明显,每次只能用一半的内存.
回到食堂上~~~
梁非凡大怒,把老板喊过来,训了一通.所以老板想了个法子,他把整张分成两块,每次只让阿姨在一块上菜,等上菜发现地方不够了,就移到另外一半上,这样就能有空间给大盘子了.
但是呢,还是有个小问题,原本吃饭讲究排场,现在一张桌子只能用一半,多穷酸?
乌鸦看看老板说:"我说就别吃了",刚想掀桌子,你看了看架势不对头,赶紧劝老板再想个办法.
标记 - 整理算法
标记整理算法是让所有的存活对象都向一端移动,接着清理掉末端的所有内存
.这样存活的对象就会聚集在一起,剩下的内存就可以直接清理了.
这次老板让阿姨先看哪些菜吃完了,然后把菜往同一个地方挪,这样位置不就大了嘛.
这个方法让乌鸦哥满意了,也就不掀他桌子了.
GC的发展过程
Serial 收集器
他是历史最悠久的收集器。而且光看名字就可以知道,这个收集器是单线程的(Serial:串行的)。
这意味着只有一个线程清理,不仅如此,用户线程在清理时必须终止(防止在清理过程中还会产生垃圾)
这个是Serial收集器的“Stop The World”。
ParNew/Parallel Scavenge 收集器
ParNew/Parallel Scavenge 收集器是两个多线程的收集器.
不同的是,ParNew能配合CMS收集器使用.
CMS 收集器
CMS收集器基于"标记 - 清除" 算法,牺牲了吞吐量来换取垃圾回收速度.
它的运作过程分为四个步骤:
- 初始标记
- 仍会"stop the world",但是速度很快,因为只是简单标记GC Root可达的对象(存活的对象). 相当于你们在吃饭的时候阿姨喊你们停一下,看了看哪些菜没吃完.然后让你们继续吃.
- 并发标记
- 从"初始标记"阶段标记的对象开始找出所有存活的对象. 因为是并发执行的,所以会存在新生代变成老年代,或者老年代的对象引用发生改变的情况,这些再后面都是要重新标记的.
- 重新标记
- 会导致"stop the world",这个阶段需要标记整个老年代的存活对象.
- 并发清除
- 并发清除未被标记的对象. 但是因为线程还会运行,还会不断产生垃圾.而且这部分垃圾无法在这次清理时被清除, 只能等下次清理.称为"浮动垃圾".
G1收集器
G1收集器是垃圾回收技术里程碑式成果之一,设计的目的是在维持高吞吐量的同时还能缩短内存回收时的停顿时间.至JDK14为止,G1还是默认的GC策略
特点:
- 使用Region部分取代分代的作用
- 可以由用户指定期望的停顿时间
G1之前的收集器,都有明确的垃圾收集的范围(新生代,老年代 etc),而G1将堆分为很多歌固定大小的区域(Region),每一个区域都能根据需要扮演不同的角色(新生代空间,老年代空间,Eden空间).
而且G1还有一类特殊的类型,巨型区域(Humongous Region),用来存放哪些大对象,判断的依据是对象是否超过50%Region的存储空间.
G1的运作分为以下四个步骤:
- 初始标记
- STW(stop the world),标记处GC Root 直接可达的对象
- 并发标记
- 对对象进行可达性分析,耗时长
- 最终标记
- 标记在并发标记时留下的少量STAB记录.
- 筛选回收
- 按照Region回收价值和时间进行排序,根据用户指定的停顿时间进行回收工作,回收部分Region.
ZGC
设计目的:
- 最大停顿时间少于10ms
- 停顿时间不会随着堆大小的变化而变化
- 支持8MB到16TB的堆
特点:
- 并发的
- 少数操作需要STW,大部分并发执行
- 基于Region
- 完全取消了分代的概念,使用Region/Page进行划分
- 压缩
- 解决了内存碎片化的问题
- 支持 NUMA架构
- 染色指针(标志性设计)
- 之前如果要在对象中添加额外信息的话,需要在对象头中添加,但是ZGC选择在指针中添加额外信息,使得标记只与对象的引用有关.
- 读屏障
- 用于对象引用地址是否满足条件
技术创作101训练营
- JQuery中文日期控件
- Silverlight中的帧
- 窗口自动弹出浏览器显示广告的问题
- Instagram 开源用于 Python 3的MonkeyType 工具
- 拼凑了几个自定义的Panel(包括FishEyePanel,WrapPanel等几个常用的布局)
- jquery获取父级一级节点的序号
- Docker容器学习梳理--基础知识(2)
- Blend生成的TransformGroup如何引用?
- 今日头条写新闻机器人获吴文俊人工智能科技发明奖
- Docker容器学习梳理--应用程序容器环境部署
- 异步方式访问网页
- Silverlight:利用Panel实现自定义布局
- 《物联网智能终端信息安全白皮书》再次敲响物联网时代警钟
- Gitlab可视化代码树插件-Octotree
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【剑指Offer】树的子结构
- 【剑指Offer】合并两个排序的链表
- Python实战之特定文本提取,挑战高效办公的第一步
- 【剑指Offer】调整数组顺序使奇数位于偶数前面
- 【剑指Offer】链表中倒数第 k 个节点
- 【剑指Offer】调整数组顺序使奇数位于偶数前面
- 【剑指Offer】复杂链表的复制
- 【剑指Offer】二叉树中和为某一值的路径
- 【剑指Offer】二叉搜索树的后序遍历序列
- 【剑指Offer】Ⅲ. 从上到下打印二叉树
- scRepertoire||单细胞免疫组库分析:R语言应用(二)
- 【剑指Offer】Ⅱ. 从上到下打印二叉树
- 【剑指Offer】I. 从上到下打印二叉树
- C#还能这么玩?“诺基亚大屏独显计算器”来咯!
- 【剑指Offer】栈的压入、弹出序列