GC详解
GC 的作用域
口诀:关于垃圾回收:分代收集算法 ==不同的区域使用不同的算法==
Young代: GC频繁区域
Old代:GC次数较少
Perm代:不会产生GC!
一个对象的历程!
JVM在进行GC时,并非每次都是对三个区域进行扫描的!大部分的时候都是指的新生代!
两个类型:
普通GC:只针对新生代 【GC】
全局GC:主要是针对老年代,偶尔伴随新生代! 【Full GC】
GC四大算法
引用计数法
特点:每个对象都有一个引用计数器,每当对象被引用一次,计数器就+1,如果引用失效,则计数器-1,如果为0,则GC可以清理;
缺点:
-
计数器维护麻烦!
-
循环引用无法处理!
JVM 一般不采用这种方式
现在一般使用可达性算法,GC Root...
==复制算法==
年轻代中,就是使用的复制算法!
1、一般普通GC 之后,差不多Eden几乎都是空的了!
2、每次存活的对象,都会被从 from 区和 Eden区等复制到 to区,from 和 to 会发生一次交换;记住一个点就好,谁空谁是to,每当幸存一次,就会导致这个对象的年龄+1;如果这个年龄值大于15(默认值,后面我们会讲解调整),就会进入养老区!
优点:没有标记和清除的过程!效率高!没有内存碎片!
缺点:==需要浪费双倍的空间==
Eden 区,对象存活率极低! 统计:99% 对象都会在使用一次之后,引用失效!推荐使用 ==复制算法==
标记清除算法
老年代一般使用这个,但是会和我们后面的整理压缩一起使用!
优点:不需要额外的空间!
缺点:两次扫描,耗时较为严重,会产生内存碎片,不连续!
标记清除压缩!
减少了上面标记清除的缺点:没有内存碎片!但是耗时可能也较为严重!
那我们什么时候可以考虑使用这个算法呢?
在我们这个要使用算法的空间中,假设这个空间中很少,不经常发生GC,那么可以考虑使用这个算法!
小总结
内存效率:复制算法 > 标记清除算法 > 标记整理(时间复杂度!)
内存整齐度:复制算法=标记整理>标记清除算法
内存利用率:标记整理 = 标记清除算法 > 复制算法
从效率来说,复制算法最好,但是空间浪费较多!为了兼顾所有指标,标记整理会平滑一点,但是效率不尽人意!
难道就没有一种最优的算法吗?思考一下:
答案:没有!没有最好的,只有最合适的!=> 分代收集算法:不同的区域使用不同的算法!
年轻代:
相对于老年区,对象存活率低!
Eden 区,对象存活率极低! 统计:99% 对象都会在使用一次之后,引用失效!推荐使用 复制算法
老年代:
区域比较大,对象存活率较高!
推荐使用:标记清除压缩!
JVM 垃圾回收的时候如何确定垃圾,GC Roots?
什么是垃圾:简单地说,就是不在被引用的对象!
Person person = null;
如果我们要进行垃圾回收,第一步:判断这个对象是否可以回收!
引用计数法!(上面已经谈过)
Java中,引用和对象都是有关联的,如果要操作对象,就要通过引用进行;
可达性分析算法!
一切都是从 GC Root 这个对象开始遍历的,只要在这里面的就不是垃圾!
什么是Gc Root,(4种)
1、虚拟机栈中引用的对象!
2、类中静态属性引用的对象
3、方法区中的常量
4、本地方法栈中 Native 方法引用的对象!