? 博客主页:@风一样的美狼子
? 欢迎关注:?点赞?收藏?留言
?系列专栏: 《云平台实战》、《Linux随你玩-实操》
?在阳光下灿烂,风雨中奔跑,泪水中成长,拼搏中展望。?
?一起加油,去追寻、去成为更好的自己!?
文章目录
前言1、GC2 、GC工作机制详解3、 怎么检测出垃圾3.1、引用计数法3.2、可达性分析算法: 4、回收算法5、分代收集算法5.1、分代的垃圾回收策略:5.2、分代垃圾回收器工作机制5.2、如何划分? 6、为什么要运用分代垃圾回收策略?7、结语
前言
承接上文Java笔记简要总结-JDK与JVM,补齐因时间问题未写完的GC相关内容,直接进入主题,GO!
1、GC
垃圾收集器一般必须完成两件事:检测出垃圾;回收垃圾。
2 、GC工作机制详解
垃圾收集器一般必须完成两件事:检测出垃圾;回收垃圾。:
1、GC是负责回收所有无任何引用对象的内存空间。
注意:垃圾回收回收的是无任何引用的对象占据的内存空间而不是对象本身
2、GC回收机制的两种算法:
a、引用计数法
b、可达性分析算法
3、 怎么检测出垃圾
3.1、引用计数法
给一个对象添加引用计数器,每当有个地方引用它,计数器就加1;引用失效就减1。
问题来了,如果我有两个对象A和B,互相引用,除此之外,没有其他任何对象引用它们,实际上这两个对象已经无法访问,即是我们说的垃圾对象。但是互相引用,计数不为0,导致无法回收,所以还有另一种方法:
3.2、可达性分析算法:
以根集对象为起始点进行搜索,如果有对象不可达的话,即是垃圾对象。
这里的根集一般包括java栈中引用的对象、方法区常良池中引用的对象、本地方法中引用的对象等。
总之,JVM在做垃圾回收的时候,会检查堆中的所有对象是否会被这些根集对象引用,不能够被引用的对象就会被垃圾收集器回收。
4、回收算法
标记-清除算法:标记无用对象,然后进行清除回收。缺点:效率不高,无法清除垃圾碎片。复制算法:按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一半。标记-整理算法:标记无用对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。此算法结合了“标记-清除”和“复制”两个算法的优点分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年代采用标记整理算法。5、分代收集算法
5.1、分代的垃圾回收策略:
不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。
5.2、分代垃圾回收器工作机制
年轻代(Young Generation)、年老代(Old Generation)、持久代(Permanent Generation)。
持久代主要存放的是类信息,所以与java对象的回收关系不大,
与回收息息相关的是年轻代和年老代。
将对象按其生命周期的不同划分成:
老生代和新生代,新生代默认的空间占比总空间的 1/3,老生代的默认占比是 2/3。
新生代使用的是复制算法,新生代里有 3 个分区:Eden、To Survivor、From Survivor,它们的默认占比是 8:1:1,它的执行流程如下:
把 Eden + From Survivor 存活的对象放入 To Survivor 区; 清空 Eden 和 From Survivor
分区; From Survivor 和 To Survivor 分区交换,From Survivor 变 To Survivor,To Survivor 变 From Survivor。 每次在 From Survivor 到 To Survivor
移动时都存活的对象,年龄就 +1,当年龄到达 15(默认配置是 15)时,升级为老生代。大对象也会直接进入老生代。老生代当空间占用到达某个值之后就会触发全局垃圾收回,一般使用标记整理的执行算法。以上这些循环往复就构成了整个分代垃圾回收的整体执行流程。
5.2、如何划分?
将对象按其生命周期的不同划分成:
年轻代(Young Generation)、年老代(Old Generation)、持久代(Permanent Generation)。
持久代主要存放的是类信息,与回收息息相关的是年轻代和年老代。
年轻代:是所有新对象产生的地方。
年轻代被分为3个部分: Enden区和两个Survivor区(From和to)
当Eden区被对象填满时,就会执行Minor GC。并把所有存活下来的对象转移到其中一个survivor区(假设为from区)。Minor GC同样会检查存活下来的对象,并把它们转移到另一个survivor区(假设为to区)。这样在一段时间内,总会有一个空的survivor区。经过多次GC周期后,仍然存活下来的对象会被转移到年老代内存空间。通常这是在年轻代有资格提升到年老代前通过设定年龄阈值来完成的。需要注意,Survivor的两个区是对称的,没先后关系,from和to是相对的。
年老代:
在年轻代中经历了N次回收后仍然没有被清除的对象,就会被放到年老代中。对于年老代和永久代,就不能再采用像年轻代中那样搬移腾挪的回收算法,通常会在老年代内存被占满时将会触发Full
GC,回收整个堆内存。
持久代: 因存放的都是静态文件,比如java类、方法等。所以持久代对垃圾回收没有显著的影响。
年轻代:涉及了复制法;年老代:涉及了“标记-整理(Mark-Sweep)”的算法。
6、为什么要运用分代垃圾回收策略?
在java程序运行的过程中,会产生大量的对象,因每个对象所能承担的职责不同所具有的功能不同所以也有着不一样的生命周期,有的对象生命周期较长,比如Http请求中的Session对象,线程,Socket连接等;有的对象生命周期较短,比如String对象,由于其不变类的特性,有的在使用一次后即可回收。
试想,在不进行对象存活时间区分的情况下,每次垃圾回收都是对整个堆空间进行回收,那么消耗的时间相对会很长,而且对于存活时间较长的对象进行的扫描工作等都是徒劳。因此就需要引入分治的思想,
所谓分治的思想就是因地制宜,将对象进行代的划分,把不同生命周期的对象放在不同的代上使用不同的垃圾回收方式。
7、结语
各位看官今天就到此为止,此系列简要笔记后续会不断更新,? 欢迎关注:?点赞?收藏?留言!