回收哪些内存:
虚拟机内存中的程序计数器,虚拟机栈,本地方法栈都是线程私有的,其生命周期随线程而生,随线程而灭,他们的内存分配及回收都具备确定性,不需要垃圾回收器参与;java堆和方法区则不一样,这两部分的内存分配及回收都是动态的,垃圾回收器关注的就是这两部分内存。
对象死了吗:
java堆的垃圾回收:判断一个对象是否已经可以被回收,有两种算法:引用计数算法,可达性分析算法。其中引用计数算法没法避免循环引用的问题,不用于实际虚拟机;可达性分析算法以GC roots作为起始点,向下遍历引用链,无法关联到的对象,都可以被回收。
方法区的垃圾回收:方法区内的垃圾回收主要包括两部分:废弃常量,无用的类。其中废弃常量的判定条件:没有被引用到;无用的类的判定条件:该类的所有实例对象都已被回收,加载该类的ClassLoader已被回收,该类对应的Class对象没有被引用。
引用分类:
强引用:Object obj = new Object()的引用关系就是强引用,强引用只有不可达的情况下才可被回收;
软引用:SoftReference,在发生内存溢出之前,将会把这些对象列进回收范围之中;
弱引用:WeakReference,在下一次垃圾回收时被回收;
虚引用:不会对对象的生存时间造成任何影响,为对象设置虚引用的目的就是在被回收时收到一个系统通知。
如何回收:
标记-清除算法:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记对象。效率不高而且产生大量不连续的空间碎片。用于java堆老生代或方法区。
复制算法:将内存分为Eden(80%),fromSurvivor(10%),toSurvivor(10%),分配内存时使用Eden区和fromSurvivor区,内存回收之后将存活的对象复制到toSurvivor区,将Eden区和fromSurvivor内存清空。用于java堆的新生代。
标记-整理算法:首先标记所有存活对象,然后让所有存活对象向一端移动,然后清理掉所有端边界以外的内存。用于java堆老生代或方法区。