阅读了大佬写的垃圾回收的文章,记录下笔记
原文地址:https://blog.youkuaiyun.com/Java_3y/article/details/121414329
1.什么是垃圾?
只要对象不再被使用就是垃圾。
2.如何判断为垃圾?
可达性分析算法和引用计数法,jvm使用的可达性分析算法。
引用计数:对象被引用则+1,引用失败则-1,如果为0,则说明没有被引用,缺点是无法解决循环依赖;
可达性分析算法:从 GC Roots 出发,向下搜索,当对象到 GC Roots 没有任何直接或间接的引用就说明该对象是垃圾;
3.哪些对象可以作为 GC Roots?
如虚拟机栈的栈帧、类的静态变量、常量、java的本地方法 等活跃的引用。
4.常见的垃圾回收算法?
标记清除、标记复制、标记整理。
第一步都是标记那些没有被GC Roots引用的垃圾对象;
标记清除:标记完后可以直接清除,但是这样会存在内存碎片,导致内存空间不连续;
标记复制:标记完后,先不直接清除,而是将其活着的对象复制另一块干净的空间上,再把刚刚的空间全部清除,缺点是空间利用率低;
标记整理:标记完后再当前这一块空间内,将活的对象移动到一边,将垃圾移动到另一边,然后将垃圾清除
5.堆为什么要分代?
大部分的对象生命周期都很短,只有少部分可以存活很长时间,垃圾回收时会导致stop the world(应用停止访问),就是垃圾回收时会短时间内程序不能正常运行,因为程序继续运行会产生新的对象,新的垃圾,JVM就没法搞了。所以为了缩短stop the world的时间,提高GC的内存分配速率,就在物理上或者逻辑上进行分区,死得快的区域叫年轻代,活得久的叫老年代;
JDK8及以下都有分代的概念,但是高版本使用的垃圾收集器ZGC是没有分代概念的
6.有哪些常见的垃圾收集器?
年轻代:Seria、Parallel Scavenge、ParNew
老年代:Serial Old、Parallel Old、CMS
Serial是单线程的,Parallel是多线程。
这些垃圾收集器实际上就是「实现了」垃圾回收算法(标记复制、标记整理以及标记清除算法)。
「年轻代」的垃圾收集器使用的都是「标记复制算法」。
7.对象什么时候从年轻代到老年代?
a.如果对象太大,在创建时就直接到老年代了,因为年轻代的Survivor区域放不下那么大的对象;
b.年轻代中的对象每经过一次Minor GC,年龄就+1,年龄达到默认的15就会到老年代;
8.什么是Minor GC?什么时候触发?
Minor GC 就是「年轻代」的GC。当Eden区空间不足时,就会触发Minor GC。
Minor GC 不会去扫描老年代的对象,内存空间中有一条分割线分割年轻代和老年代,从GC Roots出发,如果对象处于老年代的区域就不会继续往下走了。
9.如果解决年轻代对象被老年代对象所引用?
HotSpot虚拟机下 有「card table」(卡表)来避免全局扫描「老年代」对象;堆内存的每一小块区域形成一个 卡页,卡表就是卡页的集合,扫描时如果发现这个卡页中有跨代的引用,那这个卡页就被标记为脏页;Minor GC 的时候,先找到所有的脏页,然后把里面的对象加入到GC Roots下,表示有对应引用,不是垃圾,就不会回收这些被老年代引用的对象了,也避免了去扫描整个老年代了。