JVM垃圾回收篇
点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人。
文章不定期同步公众号,还有各种一线大厂面试原题、我的学习系列笔记。
基础概念
- GC=jvm垃圾回收,垃圾回收机制是由垃圾回收器Garbage Collection来实现的。进行GC的线程是后台的守护进程(后台运行、执行特定任务),它是一个低优先级进程;当可用内存低到一定程度时,自动运行(自启),从而实现对内存的回收,故垃圾回收的时间不确定;
- 浮动垃圾:jvm回收垃圾的同时,垃圾还在尝试产生,这些就是"浮动垃圾",即“floating Garbage”,只能等到下次GC的时候清理
- 并行收集:垃圾回收器工作时,用户线程停止,只有多个垃圾回收线程在并行地收集垃圾
- 并发收集:垃圾回收时,用户线程不停止,而是直接和垃圾回收线程并发地工作
如何判断对象是否是垃圾?
两种方法:引用计数法、可达性分析法(常用这种)
- 引用计数法
每个对象都有一个引用计数器,当有地方引用该对象时,计数器+1;删除引用或引用失效时,计数器-1;当计数器=0时,说明对象没有被引用则可以被JVM回收;
优点:实现简单,判断效率高
缺点:不能解决循环引用问题
- 可达性分析
jvm中有一部分对象可被称为【GC roots对象】,如:被栈中引用的对象、被常量引用的对象、被静态变量引用的对象,从【GC roots对象】开始向下遍历,遍历过程中与【GC roots对象】形成通路的对象则为'可达'对象=存活的对象=尚存在引用的对象,否则为'不可达'对象=死亡的对象=不存在引用的对象,当某个对象不可达时,说明对象没有被引用则可以被JVM回收
当对象被判定为垃圾对象后有何方法回收?
5种gc算法
- 引用计数法
每个对象都会有一个引用计数器,对象增加一个引用则计数器+1,减少一个引用则计数器-1,垃圾回收时,只回收计数器为0的对象。
缺点:无法处理循环引用的情况
- 标记清除算法
分为标记阶段和清除阶段,在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象,而未被标记的对象就是未被引用的垃圾对象;然后,在清除阶段,清除所有未被标记的对象。
缺点:标记清除后会产生大量不连续的内存碎片,内存碎片太多可能会导致以后程序运行过程中需要分配较大内存对象时,无法找到足够的连续的内存
- 标记整理算法
标记过程仍然与"标记清除"算法一样,但是后续步骤不是直接对未标记的对象进行清除,而是先让所有标记的对象都向一端移动,然后直接清除掉该端边界以外的内存,解决了没有足够大的连续内存的问题
- 复制算法
将可用的内存按照容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将活着的对象复制到另外一块上面,然后再把使用过的那一半内存空间一次清理掉。每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况。
缺点:可用内存缩小为原来的一半。
- 分代收集算法
java堆分成新生代和老年代,分带收集算法=新生代采用赋值算法+老年代采用标记整理算法。在新生代中,每次垃圾回收时都发现大批对象的死去,只有少量存活,故采用复制算法可以只付出少量存活对象的复制成本就可以完成收集;而老年代中因为对象存活率高,没有足够的空间让出来作垃圾回收,故使用“标记整理”算法来进行回收。
谁来回收?
用7种垃圾收集器来回收,可以对应地记忆:
| 串行收集器 | 并行收集器 | 吞吐量收集器 |
|---|---|---|
| 串行老年代收集器 | CMS收集器 | 吞吐量老年代收集器 |
| G1收集器 | ||
| 如上,串行收集器<->串行老年代收集器 |
||
| 吞吐量收集器<->吞吐量老年代收集器 |
||
| 并行收集器<->CMS收集器 |
||
| 再加上一个G1收集器,共7种收集器,这7种收集器可分别作用于新生代和老年代: |
||
![]() |
||
| 图中上下半部为新生代、老年代对应可用的收集器,连线代表可以结合使用 |
- 串行收集器(Serial收集器)
- 作用于新生代,故使用复制算法;
- 仅仅使用一个线程完成垃圾收集工作;
- 在垃圾收集时必须暂停其他所有的工作线程(stop-the-world),直到垃圾收集结束;
- 专心做垃圾收集故效率比较高,使用【-XX:+UseSerialGC】打开

- 并行收集器(ParNew收集器)
- 作用于新生代,故使用复制算法;
- 并行收集器其实是串行收集器的多线程版本,与Serial收集器唯一不同的地方就是在垃圾收集过程中使用多个线程并行收集,其他全部和串行收集器相同
- 它默认开启的收集线程数与CPU的数量相同
- 使用【-XX:UseParNewGC】打开;
除了Serial收集器,就只有它能和CMS收集器混合使用

吞吐量收集器(ParallelScavenge 收集器)
- 作用于新生代,故使用复制算法;
- 吞吐量收集器的目的是追求高吞吐量,吞吐量=运行用户代码时间/(运行用户代码时间+运行垃圾收集时间);
- 使用【-XX:+UseParallelGC】打开;使用【-XX:MaxGCPauseMillis】指定垃圾收集最大停顿时间,但并非越小越好;
- 使用多个GC线程来完成垃圾收集
- 会引起stop-the-world(垃圾收集停顿时间:垃圾收集的时候,所有java线程被挂起,除了垃圾收集器的线程,此时navtive相关代码可执行但不能与JVM交互,故stop-the-world是大家的敌人)
- 最大的特点是'GC自适应策略'':打开GC自适应策略【-XX:+UseAdaptiveSizePolicy】,则不用再手动设置'年轻代:老年代'的大小、'Eden区:survivor区'的大小、对象晋升老年代的年龄,系统会根据实时性能去动态设置这些参数以便达到最高的吞吐量、最优的停顿时间

串行老年代收集器(Serial Old收集器)
- 因为作用于老年代,所有采用'标记整理'算法
- 和串行收集器一样,只是它作用于老年代,是串行收集器的老年代版本

CMS收集器
- 作用于老年代,故使用'标记整理'算法;
- 以获取最短的垃圾收集停顿时间为目标,重视响应速度和用户体验的应用;
- CMS收集器的内存回收过程是与用户线程一共并发执行的;
- 使用【-XX:+UseConcMarkSweepGC】打开;
- 步骤:初始标记->并发标记->重新标记->并发清除,初始阶段=标记由【GC roots】直接到达的对象,并发标记=标记由【GC roots】间接到达的对象,重新标记=修正在'并发标记'期间由于用户程序运行而导致标记变动的标记,并发清除=清除已标记的对象

- 吞吐量老年代收集器(Parallel Old收集器)
- 因为作用于老年代,所有采用'标记整理'算法
- 和吞吐量收集器一样,只是它作用于老年代,是吞吐量收集器的老年代版本
- 使用【-XX:+UseConcMarkSweepGC】打开

- G1收集器
- 可作用于年轻代/老年代,jdk1.9之后的默认垃圾收集器
- 使用【-XX:+UseG1GC】打开
- G1收集器的内存回收过程是与用户线程一起并发执行的;
- G1收集器不会产生内存碎片,会把内存碎片收集后形成大的内存块
- G1收集器最大的特点是把堆的内存分成一块块大小相同的区域(region),保留年轻代、老年代的概念,但年轻代、老年代也是被清晰地分为一个个区域
- G1追求最小的gc停顿时间,并且可用参数指定gc停顿时间,也就是建立了可以预测的gc停顿时间模型,原理:因为G1收集器把堆分成了一块块大小相同的区域,每个区域可以回收的空间大小不同,G1会在后台把每个区域的回收价值(回收价值=可回收的空间大小+回收时间成本)由大到小维护成一张优先级列表,回收是先回收价值大的区域;每个区域的大小可以通过【-XX:G1HeapRegionSize】参数指定,大小区间最小1M、最大32M,一定要是2的幂次方,默认把堆内存按照2048份均分,每个区域被标记了E、S、O和H,这些区域在逻辑上被映射为Eden、Survivor、老年代Old和Humongous去(用来存放大对象)
- 步骤:初始标记->并发标记->重新标记->筛选回收,初始阶段=标记由【GC roots】直接到达的对象,并发标记=标记由【GC roots】间接到达的对象,重新标记=修正在'并发标记'期间由于用户程序运行而导致标记变动的标记,筛选回收=对各个region计算回收价值(回收价值=可回收的空间大小+回收时间成本),并按照用户设置的停顿时间来制定回收计划


默认的垃圾回收器
jdk1.7和jdk1.8: 年轻代默认'吞吐量垃圾收集器'(即Parallel Scavenge), 老年代默认'吞吐量老年代收集器'(即Parallel Old)
jdk1.9:默认G1垃圾收集器
OK,如果文章哪里有错误或不足,欢迎各位留言。
创作不易,各位的「三连」是二少创作的最大动力!我们下期见!
JVM垃圾回收篇的更多相关文章
- JVM垃圾回收?看这一篇就够了!
深入理解JVM垃圾回收机制 1.垃圾回收需要解决的问题及解决的办法总览 1.如何判定对象为垃圾对象 引用计数法 可达性分析法 2.如何回收 回收策略 标记-清除算法 复制算法 标记-整理算法 分带收集 ...
- Java进阶 JVM 内存与垃圾回收篇(一)
JVM 1. 引言 1.1 什么是JVM? 定义 Java Vritual Machine - java 程序的运行环境(Java二进制字节码的运行环境) 好处 一次编译 ,到处运行 自动内存管理,垃 ...
- JVM学习笔记——垃圾回收篇
JVM学习笔记--垃圾回收篇 在本系列内容中我们会对JVM做一个系统的学习,本片将会介绍JVM的垃圾回收部分 我们会分为以下几部分进行介绍: 判断垃圾回收对象 垃圾回收算法 分代垃圾回收 垃圾回收器 ...
- jvm - 垃圾回收
jvm - 垃圾回收 注意 : 本系列文章为学习系列,部分内容会取自相关书籍或者网络资源,在文章中间和末尾处会有标注 垃圾回收的意义 它使得java程序员不再时时刻刻的关注内存管理方面的工作. 垃圾回 ...
- Java虚拟机学习笔记——JVM垃圾回收机制
Java虚拟机学习笔记——JVM垃圾回收机制 Java垃圾回收基于虚拟机的自动内存管理机制,我们不需要为每一个对象进行释放内存,不容易发生内存泄漏和内存溢出问题. 但是自动内存管理机制不是万能药,我们 ...
- JVM垃圾回收机制总结:调优方法
转载: JVM垃圾回收机制总结:调优方法 JVM 优化经验总结 JVM 垃圾回收器工作原理及使用实例介绍
- JVM内存管理和JVM垃圾回收机制
JVM内存管理和JVM垃圾回收机制(1) 这里向大家描述一下JVM学习笔记之JVM内存管理和JVM垃圾回收的概念,JVM内存结构由堆.栈.本地方法栈.方法区等部分组成,另外JVM分别对新生代和旧生代采 ...
- JDK分析工具&JVM垃圾回收(转)
转自:http://blog.163.com/itjin45@126/blog/static/10510751320144201519454/ 官方手册:http://docs.oracle.com/ ...
- 老李分享:jvm垃圾回收
老李分享:jvm垃圾回收 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908821478 ...
随机推荐
- Vue中图片的加载方式
一.前言 VUE项目中图片的加载是必须的,那么vue中图片的加载方式有哪些呢,今天博主就抽点时间来为大家大概地捋一捋. 二.图片的加载方法 1.在本地加载图片(静态加载) 图片存放assets文件夹中 ...
- error C4996: 'std::_Copy_impl'
以下代码段在VS2008编译可以通过,只是会提示不安全: std::vector<unsigned char> fileData ="asdfsfsfsfsdf";// ...
- Java并发机制(8)--concurrent包下辅助类的使用
Java并发编程:concurrent包下辅助类的使用 整理自:博客园-海子-http://www.cnblogs.com/dolphin0520/p/3920397.html 1.CountDown ...
- 用 Java 写一个线程安全的单例模式(Singleton)?
请参考答案中的示例代码,这里面一步一步教你创建一个线程安全的 Java 单例类.当我们说线程安全时,意思是即使初始化是在多线程环境中,仍然能保证单个实例.Java 中,使用枚举作为单例类是最简单的方式 ...
- JDBC几个接口分区叫什么?它们分别有什么用?
DirverManager类:是JDBC的管理层,作用于用户和驱动之间.该类负责注册和加载JDBC驱动.Connection接口:代表与数据库的链接,并拥有创建SQL语句的方法,以完成基本的SQL操作 ...
- ReentrantLock 源代码之我见
ReentrantLock,英文意思是可重入锁.从实际代码实现来说,ReentrantLock也是互斥锁(Node.EXCLUSIVE).与互斥锁对应的的,还有共享锁Node.SHARED Reent ...
- JVM学习思考
毕业以来技术上一直没有太大进步,仔细一想可能是没有做技术分享,我喜欢把学习总结记录在印象笔记中,那么理解的是对是错也就没人能评判一下.为了技术进步,接下来将陆续把一些学习总结迁移到博客园中,欢迎大家多 ...
- websocket 实现简单网页版wechat
1.群聊 web - socket--基于TCP/UDP http - 无状态的短链接 长连接:客户端和服务器保持永久性的链接,除非有一方主动断开, 轮询:客户端和服务端不断连接,然后断开,请求响应; ...
- 常用缓存(cache)淘汰算法(LFU、LRU、ARC、FIFO、MRU)
缓存算法是指令的一个明细表,用于决定缓存系统中哪些数据应该被删去. 常见类型包括LFU.LRU.ARC.FIFO.MRU. 最不经常使用算法(LFU): 这个缓存算法使用一个计数器来记录条目被访问的频 ...
- Linux文件管理 | Liunx 常用命令
文件与目录基本操作 目录: 一.显示文件内容 cat 命令 more 命令 less 命令 head 命令 tail 命令 二.文件内容查询(grep) 三.文件查找命令 find 命令 locate ...
