java虚拟机面试干货【肆】_垃圾回收:判断条件


上篇文章:java虚拟机面试干货【叁】_JVM内存结构


由上文我们可以大略总结出,在JVM中线程私有的变量是保存在栈上的,公共的对象保存在堆上,而静态变量保存在堆空间中的方法区(PermGen)上。由于系统分配给JVM的内存空间也是有限的,当一个对象不再使用时我们应该把它回收以释放空间,下面就说说垃圾回收(GC)的事儿。


对象是否存活


垃圾回收的第一步就是要判断,对象是否存活,即是否需要回收。通常情况下,判断对象是否存活的方式有两种:


1.引用计数


对象时维护一个变量,当有其他对象的引用的时候,该变量加一。垃圾回收时只回收那些变量为零的对象。但这个算法有个问题就是,当两个对象相互引用,而它们任意一个都再没有被第三个对象引用,此时它们基于这个算法是不会被回收的,就是造成内存泄漏。因此JVM并没有使用这个算法,而是使用下面的可达分析算法。


2.可达分析


实现思路就是通过一系列的称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连的时候,则证明该对象已不可用。


在java实现中可用做GC Roots的对象有:


虚拟机栈(栈帧中的本地变量表)引用的对象;

方法区中类静态属性引用的对象;

方法区中常量引用的对象;

本地方法中Native方法引用的对象;


4种引用类型


在GC实现了可达分析算法后,我们还有种需求,希望可以将对象设置回收优先级,一些不重要的对象可以优先回收从而保证重要对象的存活时间。因此从JDK 1.2开始,java提出了4种引用类型,分别为强引用、软引用、弱引用和虚引用。


1.强引用


即代码中普遍存在的,由我们通过new等方式正常声明出来的对象。只要强引用还存在,GC就永远不会回收这部分对象。


2.软引用


即WeakReference,用来描述一些有用但非必需的对象。当GC过程中,只有在将要发生内存溢出之前才会回收软引用关联着的对象。


3.弱引用


即SoftReference,用来描述非必需对象。在GC过程中,不论内存是否足够,只要发现弱引用关联的对象就会回收。


4.虚引用


即PhantomReference,又称幽灵引用或幻影引用,最弱的引用关系。虚引用关联对象不会影响其生存时间,也无法通过虚引用来获取一个对象实例。虚引用的存在只是为了在这个对象被GC回收的时候收到个系统通知。


关于finalize()方法


我们知道,finalize()是Object八大基本方法之一(详见此文),它的意义就在于当对象被GC回收时,会触发这个方法。这次我们站在GC回收器的角度重新看看这个过程:


当一个对象被判定没有和GC Roots相连接的引用链后,它将被进行两次标记。第一次标记是看看它有没有自行实现finalize方法,如果没有实现则直接进行回收;如果实现了,则将这个对象放置进一个名为F-Queue的队列,排队触发finalize方法。期间会进行第二次标记,如果第二次标记该对象仍不存在到GC Roots的引用链(finalize方法中可实现将该对象重新引用),则将其回收。需要注意的一点是,这里不承诺等待finalize方法运行结束


关于方法区回收


方法区主要存放已被JVM加载的类信息、常量、静态变量等数据。而在GC回收中,我们主要关注废弃常量无用的类,下面说说判断依据。


当常量池中的一个常量没有任何引用的时候,就会将其回收。比如字符换"abc",在系统内没有任何一个字符串值为"abc"时,则将其回收。


而无用的类即对类的卸载条件,在上篇文章中总结过,权且再贴于此:


1.该类素有的实例都已经被回收,即java堆中不存在任何该类的实例;

2.加载该类的ClassLoader已经被回收;

3.该类对应的java.lang.Class对象没有再任何地方被引用,无法在任何地方通过反射访问该类的方法;



下篇文章我们说说具体的GC回收算法。

你可能感兴趣的:(java虚拟机)