一:如何确定对象是否为垃圾对象
1.主要原则就是看对象是否可达,而对象是否可达就是看对象是否被引用,java对象都有一个引用计数属性,每被引用一次,就+1,每被释放一次,就-1.
2.对象引用类型
(1)强引用:即使内存不够,溢出了,jvm也不会回收此类对象,当强引用对象之间的关联被切断时,才有可能被回收(如果方法内部进行引用,当方法执行完毕,就会退出方法栈,强引用一样会失效)
(2)软引用:只有jvm内存不够用时,才会回收此类对象
(3)弱引用:jvm即使内存不够用,一旦进行垃圾回收,弱引用指向的对象也会被回收
(4)虚引用: 与若引用的回收机制类似,但是无法通过虚引用来获取一个对象的真实引用,即无法通过虚引用获取对象实例 ,需要结合引用对象来使用
二:GC回收算法
1.标记-清理算法:利用可达算法(对象是否被回收),标记不可达的对象,然后清理这些不可达对象
缺点:不可达对象很可能内存是不连续的,这里对象被清理后空出来的内存空间很可能大小满足不了新的对象,最终这些内存很可能被丢失。也就是导致内存碎片的丢失,这种算法适合可达对象多的场景
2.标记-复制算法
把内存空间分成两份,一份用来存对象,一份先空着。利用可达算法,标记出不可达对象,然后把可达对象复制到另一份空的内存空间,原内存空间的对象全部删除。
缺点:空间利用不完全,浪费一般的内存空间,适合不可达对象多的场景(减少复制量)
3.标记压缩算法
与标记-清理算法类似,清理完不可达对象后,会整理内存碎片,防止内存泄漏,解决了标记-清理算法的问题
缺点:内存碎片整理开销大,适合可达对象多的场景
4.分代算法
分代算法结合了标记-清理算法与标记压缩算法,把堆分成了新生代与老年代,新生代又分为eden区,from区以及to区,所有刚刚创建出来的对象都放在eden区,当eden区满了之后,使用复制算法把可达对象从from区或者to区任意一个没有使用的内存空间,假设是to区(from区中存活的对象也会被放进to区),然后再把eden区和from区的对象都直接清理掉。另外:新生代不可达对象多,因此使用了标记-复制算法,老年大可达对象多,因此使用了标记压缩算法
新生区对象转移到老年区的条件
(1)对象太大(虚拟机参数可以调这个阈值)
(2)转移过程,如上述的to区满了,多出来的对象也是直接转移到老年区
(3)复制15次后,依然还存活的对象(对象存储该年龄的空间大小为4个bit,最大十进制是15)