1、 哪些内存需要回收?
Java堆和方法区。
程序计数器、虚拟机栈和本地方法栈生命周期和线程一样。线程结束时候内存回收。
2、 如何判断对象是否存活?
(1) 引用计数器法:每个对象添加引用计数器,根据引用数目进行计数器增减。消耗较大且不能处理两个对象互相引用的情况。
(2) 可达性分析法:从GC Roots节点向下搜索,若对象无引用链相连接。对象不可用。
GC Roots:(i)虚拟机栈中的局部变量表中的对象引用。
(ii)方法区中的静态属性和常量引用的对象。
两次标记过程:引用链为第一次标记,筛选是否执行finalize()方法(自救,且只有一次)
3、 四种引用类型
(1) 强引用:A a = new A(); a是强引用。
(2) 软引用:内存不足时释放所引用的对象。
(3) 弱引用:一旦发生GC,弱引用所关联的对象立即被回收。
(4) 虚引用:对象被回收时候收到系统通知,不能通过虚引用取得对象实例。
4、 方法区的回收
(1) 废弃常量:没有任何一个引用指向常量池中的常量。
(2) 无用的类:(i)类的所有实例被回收。
(ii)加载该类的ClassLoader被回收。
(iii)该类的Class对象没有被引用。
5、 垃圾回收线程:后台线程。(当前台线程为0时候,后台线程自动消亡)
6、 JVM垃圾回收算法
(1)三种垃圾回收算法:标记—清除、复制、标记—整理。
(2)标记—清除算法:
原理:GC roots开始扫描,标记所有存活的对象。再次扫描整个内存空间清除未标记对象。
适用场合:存活对象较多;年老代。
缺点:效率—扫描内存空间两次。空间—产生不连续内存碎片。
内存分配方式:空闲列表法。
(3) 复制算法
原理:先将内存分为两部分,每次只使用一块。一块区域使用完毕后,GC roots开始扫描,将存活对象复制到另一块。然后清理整一块区域。(只扫描一次,每次对半区进行回收)
适用场合:存活对象较少;年轻代。
缺点:原来内存划分,内存减少。需要复制移动对象。
内存分配方式:指针碰撞。
(4) 标记—整理算法
原理:GC roots开始扫描,标记所有存活的对象。让所有存活对象向一端移动,直接清理掉端边界以外的内存。
适用场合:年老代
缺点:需要移动对象;扫描两次内存空间。
优点:不会产生内存碎片。
内存分配方式:指针碰撞。
(5) 分代收集算法:根据对象存活周期的不同将内存进行划分,根据各个年代的特点采用最适当的收集算法。