什么是垃圾回收机制? 不定时的清理不可达对象,不可达对象不会立马被回收,垃圾收集器在一个 Java 程序中是自动的,不能强制执行,即使我们已经清楚的确定这块内存已经没有用处了,应该被回收掉,也不能强制执行,我们能做的只是调用 System.gc() 来建议垃圾回收器,这块内存可以回收,但垃圾收集器回收不回收,什么时候回收,都是不可知的 finalize() 方法的作用 在垃圾收集器回收对象前做必要的清理工作,这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的,该方法是在 Object 定义的,所以所有类都继承了它,子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作 新生代和老生代

添加描述 Java 中的堆是 JVM 所管理的最大的一块内存空间,在 Java 中,堆被分成了两个内存空间,分别是新生代和老年代,新生代占 1/3,老生代占 2/3 新生代中存储新创建的对象,垃圾收集器频繁的活跃在新生代,新生代又分成三个部分,分别是 Eden、from 、to,默认比例是 8:1:1,当对象创建后,对象首先存放在 Eden 区域,经历过一次垃圾回收后,如果对象还存活,就进入 from 区域或者 to 区域,新生代中的对象每经历一个垃圾回收,对象年龄加1,达到一定年龄,进入老年代 老年代中存储较为活跃的对象 如何判断对象是否存活? 引用计数法 当一个对象被创建后,年龄默认为0,每经历过一次垃圾回收,年龄就会增加1,如果年龄大于15就会存放到老年代中去,GC 线程不定期的回收,如果对象被引用,年龄加1,如果未被引用,年龄减1,如果年龄为0,会被垃圾回收机制认为是不可达对象,对其进行回收,引用计数法的缺点是很难解决循环引用的问题 根搜索算法 根搜索算法就是将名为 GC Roots 的对象作为起始点,往下进行搜索,搜索所经过的路径称为引用链(Reference Chain),当一个对象到 GC Roots 没有任何引用链,则该对象是不可达的 如何获取 GC Roots 对象? 虚拟机栈(栈帧中的局部变量区,也叫做局部变量表)中引用的对象 方法区中的类静态属性引用的对象 方法区中常量引用的对象 本地方法栈中 JNI 引用的对象 垃圾回收策略 标记清除算法 给每个对象根据是否可达做个标记,遍历标记为不可达的对象,逐个删除 应用场景:发生在老年代 优缺点: 优点

可以解决循环引用问题 必要时才回收 缺点

回收时,应用需要挂起 标记和清除的效率不高,尤其是要标记的对象很多的时候 会造成内存碎片 复制算法 如果 JVM 使用了coping 算法,当创建一个对象时,首先会存放到 Eden 区域,当扫描到对象比较活跃,就将这些活跃的对象存放在 from 区域或者 to 区域,注意,这两个区域肯定有一个为空,如果对象存到了 form 区域,如果from 区域的对象随着程序执行出现了不可达对象,会将可达对象复制到 to 区域,直接清空 from 区域 应用场景:发生在新生代 优缺点: 优点

解决碎片化问题、性能高 造成空间浪费,from 或 to 始终有一个是空的 标记压缩算法 标记压缩算法和标记清除算法类似,不同的是将对象按顺序进行排列,直接将不可达对象一块删除 任意顺序:即不考虑原先对象的排列顺序,也不考虑对象之间的引用关系,随意移动对象 线性顺序:考虑对象的引用关系,例如 a 对象引用了 b 对象,则尽可能将 a 和 b 移动到一块 滑动顺序:按照对象原来在堆中的顺序滑动到堆的一端 优缺点: 优点

解决内存碎片问题 缺点

在标记压缩时,由于排序改变了对象位置,需要更新引用 分代算法 对于新生代,采用复制算法,对于老年代,采用标记->压缩->清除算法 Minor GC 和 Full GC 区别: Minor GC:即新生代 GC ,发生在新生代的垃圾收集动作,所以 Minor GC 十分频繁,一般回收速度也较快,当 Eden 区域满时,会触发 Minor GC Full GC:即老年代 GC,发生在老年代的垃圾收集动作,所以 Full GC 很少发生,速度也较 Minor GC 慢十倍,当老年代满时,会触发 Full GC,同时会清除新生代和老年代,当永久代满时,也会触发 Full GC, JVM 的永久代中会发生垃圾回收吗? 垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完全垃圾回收 Full GC