week05_day05_GC(垃圾回收)
我们现在学虚拟机都是以hotspot为例来讲的。
GC——Garbage Collection
在JVM中,GC的功能是由垃圾回收器来完成。
研究GC,就必须要回答下面3个问题:
- 如何确定“垃圾”
- 如何回收垃圾
- 何时触发GC
···············································································································································································································
一、如何确定垃圾对象?
- 确定哪些对象已经变成了垃圾,最简单的算法就是引用计数法
给对象添加一个引用计数器
每当一个地方引用它时,计数器加1
每当引用失效时,计数器减少1
当计数器的数值为0时,也就是对象无法被引用时,表明对象不可在使用
但是这个算法存在一个致命的缺陷,无法解决循环引用的问题
为此,引入了另外一种跟搜索算法
2. 根搜索算法
这个算法的基本思想是将一系列称为“GC Roots”的对象作为起始点
从这些节点开始向下搜索
搜索所走的路径称为引用链
当一个对象到所有的GC root之间没有任何引用链相连,时,就认为该对象变成了垃圾
GC Roots包含对象呢?
虚拟机栈中引用的对象
方法区中的静态属性引用的对象
(这两种都是可用对象)
···············································································································································································································
二、如何回收垃圾对象呢?
- 标记清除算法(Mark Sweep)
缺点:易产生内存碎片 - 标记复制算法(Copy)
这个堆内存,上来不管三七二十一,先切一半,只用一半给对象分配存储空间,剩下一半不使用。
然后这一半用啊用啊快用完的时候,如果还有人来new对象,此时就会触发一次垃圾回收,复制算法把存活对象复制到另一片存储空间中,然后将原来这半边的内存全部回收掉。
然后就使用另一半存储空间给应用程序分配内存。
然后就这样循环,这半边满了移到对面,回收这半边,对面那半边满了移到这半边,回手对面那半边。 - 标记整理算法(Mark Compact)
这个算法做了两件事情:
a. 回收垃圾对象
b. 将所有存活对象向内存的同一端移动。将每一个存活对象移动到上一个存活对象之后。
所以,其内存利用率很高(不用上来就砍一半),也不会产生内存碎片。
但是,因为移动存活对象会计算上一个存活对象的地址,所以会花费很多时间,效率比较低。(用时间换空间)