1 判断对象是否是垃圾算法
1.1 引用计数算法
- 优点:执行效率高,程序执行受影响较小
- 缺点:无法检测出循环引用 情况,导致内存泄漏
1.2 可达性分析算法
- 通过判断对象的引用链是否可达来决定对象是否可以被回收
1.3 可作为GC Root的对象
- 虚拟机栈中引用的对象(栈针重点本地变量表)
- 方法区中的常量引用对象
- 方法区中的类静态属性引用的对象
- 本地方法栈中JNI(Native方法)的引用对象
- 活跃线程的应用对象
2 垃圾回收算法
2.1 标记-清除算法(Mark and Sweep)
- 标记:从根集合进行扫描,对存活的对象进行标记
- 清除:对堆内存从头到尾进行线性遍历,回收不可达对象内存
2.2 复制算法(Copying)
- 解决碎片化问题
- 顺序分配内存,简单高效
- 适用于对象存活率低的场景
2.3 标记-整理算法(Compacting)
- 标记:从根集合进行扫描,对存活的对象进行标记
- 清除:移动所有存活对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收
总结:
- 避免内存的不连续性
- 不用设置两块内存互换
- 适用于存活率高的场景
2.4 分代收集算法(Generational Collector)
- 垃圾回收算法的组合拳
- 按照对象生命周期的不同划分区域以采用不同的垃圾回收算法
- 目的:提高JVM的回收效率
3 彩蛋
3.1 JVM运行模式
- Server
- Client
3.2 Stop-the-world
- JVM 由于要执行GC而停止了应用程序的执行
- 任务一种GC算法中都会发生
- 多数GC优化通过减少Stop-the-world发生的时间来提高程序性能
3.3 Safepoint
- 分析过程中对象引用关系不会发生变化的点
- 产生Safepoint的地方:方法调用、循环跳转、异常跳转等
- 安全点数量要适中
3.4 吞吐量
运行用户代码时间/(运行用户代码时间+垃圾收集时间)
3.5 查看垃圾收集器
java -XX:+PrintCommandLineFlags -version
4 垃圾收集器
收集器 | 手机算法 | |
---|---|---|
年轻代 | Serial | 复制算法 |
ParNew | 复制算法 | |
Parallel Scavenge | 复制算法 | |
老年代 | Serial Old | 标记-整理算法 |
Parallel Old | 标记-整理算法 | |
CMS | 标记-清除算法 |
4.1 年轻代
(1)Serial 收集器
- 复制算法
- 单线程收集,进行垃圾收集时,必须暂停所有动作线程
- 简单高效,Client模式下默认的年轻代收集器
(2)ParNew 收集器
- 复制算法
- 多线程收集,其余的行为、特点和Serial收集器一样
- 单核执行效率不如Serial,在多核下执行才有优势
(3)Parallel Scavenge 收集器
- 复制算法
- 比起关注用户线程停顿时间,更关注系统的吞吐量
- 在多核下执行才有优势,Server模式下默认的年轻代收集器
- -XX:+UseAdaptiveSizePolicy 自动调节
4.2 老年代
(1)Serial Old 收集器
- 标记-整理算法
- 单线程收集,进行垃圾收集时,必须暂停所有工作线程
- 简单高效,Client模式下默认的老年代收集器
(2)Parallel Old 收集器
- 标记-整理算法
- 多线程,吞吐量优先
(3)CMS 收集器
- 标记-清除算法
- 希望JAVA垃圾回收器回收垃圾的时间尽可能短,以获取最小停顿时间为目的
- 应用运行在多CPU的机器上,有足够的CPU资源
- 有比较多生命周期长的对象
- 希望应用的响应时间短
CMS 收集过程
【1】初始标记 CMS-initial-mark
stop-the-world,这个阶段会扫描root对象直接关联的可达对象。注意不会递归的追踪下去,只是到达第一层而已。这个过程,会STW,但是时间很短。
【2】并发标记 CMS-concurrent-mark
并发追溯标记,程序不会停顿。
【3】并发预清理
查找执行并发标记阶段从年轻代晋升到老年代的对象。
【4】重新标记 CMS-remark
暂停虚拟机,扫描CMS堆中的剩余对象。在并发mark阶段,应用的线程可能产生新的垃圾,所以需要重新标记,这个阶段也是会STW。
【5】并发清除 CMS-concurrent-sweep
清理垃圾对象,程序不会停顿
【6】并发重置 CMS-concurrent-reset
并发重置状态等待下次CMS的触发
CMS 收集器缺点
【1】Concurrent Mode Failure
由于cms垃圾回收线程可以和应用的线程一起工作,那么应用线程仍然需要申请内存,如果这个时候老年代的空间已经不够用了。那么会有Concurrent Mode Failure 这样的日志输出,之后会进行一次Full GC的操作,所有的应用线程都会停止工作。
【2】浮动垃圾
由于cms垃圾回收线程可以跟应用的线程一起工作,那么应用的线程也会产生垃圾,这些称之为浮动垃圾。
【3】降低吞吐量
由于应用线程和垃圾回收线程一起工作,那么垃圾回收线程也就抢占了系统资源,会对应用的吞吐量造成一定的影响。为了保证垃圾回收过程中,应用线程有足够的内存可以使用,当堆内存的空间使用率达到68%的时候,CMS开始触发垃圾回收。
【4】内存碎片
CMS是基于标记-清除算法的,会造成内存碎片。
4.3 G1 收集器
复制+标记-整理算法
-XX:+UseG1GC
特点:
- 并行和并发
- 分代收集
- 空间整合
- 可预测的停顿
实现:
- 将整个java堆内存划分多个大小相等的Region
- 年轻代和老年代不再物理隔离
4.4 其他收集器
Epsilon GC 和 ZGC(jdk11)
5 收集器设置
【1】XX:+UseSerialGC
虚拟机运行在Client模式下的默认值,Serial+Serial Old
【2】-XX:+UseParNewGC
在JDK1.8被废弃,在JDK1.7还可以使用 ParNew+Serial Old
【3】-XX:+UseParallelOldGC
Parallel Scavenge+Parallel Old
【4】XX:+UseConcMarkSweepGC 互联网应用的选择
ParNew+CMS+Serial Old
Serial Old收集器作为CMS收集器出现Concurrent Mode Failure失败后的后备收集器使用。
【5】-XX:+UseParallelGC 后台应用程序的选择
虚拟机运行在Server模式下的默认值,Parallel Scavenge+Serial Old(PS Mark Sweep)
【6】-XX:+UseG1GC
G1+G1
来源:oschina
链接:https://my.oschina.net/u/3777515/blog/3175338