关于 Java垃圾回收机制

  笔者最近遇到超级多的关于Java中垃圾回收机制的问题,所以特地写一遍博客来和大家交流一下Java中的垃圾回收到底是什么鬼。所谓垃圾回收即使jvm觉得你这个对象没有存在的必要,将你清理出去,那么问题来了。

如何确定某个对象是需要被回收?

典型的垃圾收集算法,是怎么回收对象的?

典型的垃圾收集器有哪些?

  下面我来一个一个看问题

二、如何确定某个对象是需要被回收的

  这里我们先了解一个的问题:如果确定某个对象是“垃圾”?既然垃圾收集器的任务是回收垃圾对象所占的空间供新的对象使用,那么垃圾收集器如何确定某个对象是“垃圾”?—即通过什么方法判断一个对象可以被回收了。有些对象是jvm内存不足需要清理内存空间,会将下一轮需要回收的对象进行清理。

  在java中是通过引用来和对象进行关联的,也就是说如果要操作对象,必须通过引用来进行。那么很显然一个简单的办法就是通过引用计数来判断一个对象是否可以被回收。不失一般性,如果一个对象没有任何引用与之关联,则说明该对象基本不太可能在其他地方被使用到,那么这个对象就成为可被回收的对象了。这种方式成为引用计数法。

  这样的方法简单粗暴,而且效率很高。效率高必然会暴露一些问题,如果某些对象呗循环引用,即使你把对象赋值为null,这种算法照样不能回收。看下下面的代码

public class GcTest { public Object object = null; public static void main(String[] args) { GcTest gcTest1 = new GcTest(); GcTest gcTest2 = new GcTest(); gcTest1.object = gcTest1; gcTest2.object = gcTest2; gcTest1 = null; gcTest2 = null; } } 

  虽然gcTest1,gcTest2是null,他们指向的对象已经不会被访问到了,但是由于它们互相引用对方,导致它们的引用计数都不为0,那么垃圾收集器就永远不会回收它们。

  上面的问题已经暴露出来了,下面看看jvm是怎么解决这个问题的。为了解决这个问题,在Java中采取了可达性分析法。该方法的基本思想是通过一系列的“GC Roots”对象作为起点进行搜索,如果在“GC Roots”和一个对象之间没有可达路径,则称该对象是不可达的,不过要注意的是被判定为不可达的对象不一定就会成为可回收对象。被判定为不可达的对象要成为可回收对象必须至少经历两次标记过程,如果在这两次标记过程中仍然没有逃脱成为可回收对象的可能性,则基本上就真的成为可回收对象了。在《深入理解jvm》讲解的很仔细,笔者就简单介绍下GC Roots的概念,想深入了解的可以去读下笔者介绍的这本书。

  以下三类对象在jvm中作为GC roots,来判断一个对象是否可以被回收 (通常来说我们只要知道虚拟机栈和静态引用就够了)

  1、虚拟机栈(JVM stack)中引用的对象(准确的说是虚拟机栈中的栈帧(frames)) 。我们知道,每个方法执行的时候,jvm都会创建一个相应的栈帧(栈帧中包括操作数栈、局部变量表、运行时常量池的引用),栈帧中包含这在方法内部使用的所有对象的引用(当然还有其他的基本类型数据),当方法执行完后,该栈帧会从虚拟机栈中弹出,这样一来,临时创建的对象的引用也就不存在了,或者说没有任何gc roots指向这些临时对象,这些对象在下一次GC时便会被回收掉

  2、方法区中类静态属性引用的对象 。静态属性是该类型(class)的属性,不单独属于任何实例,因此该属性自然会作为gc roots。只要这个class存在,该引用指向的对象也会一直存在。class 也是会被回收的,在面后说明

  3、本地方法栈(Native Stack)引用的对象

  下面介绍下关于软引用(softReference)和弱引用(weakReference)的对象垃圾回收对他们做的处理

String str = new String("hello");//A SoftReference<String> sr = new SoftReference<String>(new String("java"));//B WeakReference<String> wr = new WeakReference<String>(new String("world"));//C

  上面的几个对象中回收情况如下,B在内存不足的情况下会将String对象判定为可回收对象,C无论什么情况下String对象都会被判定为可回收对象。也就是说软引用会在内存溢出(OOM)的时候回收,而弱引用无论什么情况都会在下一轮回收的时候回收掉。

  一般jvm会对这些对象回收

  1、显示地将某个引用赋值为null或者将已经指向某个对象的引用指向新的对象。

  2、局部引用所指向的对象。

  3、上面说的弱引用(weakReference)。

三、垃圾收集算法

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/231afab9e54d47a134f097cea8cc61e8.html