一、概念
垃圾回收是JVM的堆中管理内存的一种办法。JVM会在特定条件下回收无用的对象占用的内存空间。
二、判断垃圾的方法
1、引用计数法
这种判断某一对象是否是垃圾的方法的原理是:记录某个对象被引用的次数,如果引用次数是0说明是垃圾。但是有漏洞:如果两个对象互相引用,实际上这两个都是垃圾,但是由于引用次数大于0,因此永远都不会被回收。
2、可达性分析算法
原理是:从一组根对象作为起点,按照从上至下的方式搜索被根对象连接的对象是否可达。如果不可达,说明该对象是垃圾。可以作为根对象的是:虚拟机栈中引用的对象(如方法参数、局部变量等)、方法区中类静态属性引用的对象、常量引用的对象等。
三、五种引用
- 强引用:只要一个对象有强引用,那么就不会被垃圾回收
- 软引用:如果一个对象没有强引用,只有软引用。那么这个对象在发生垃圾回收且内存不足时会被垃圾回收
- 弱引用:如果一个对象没有强引用,只有弱引用。那么这个对象只要发生了垃圾回收就会被回收
- 虚引用:和弱引用的区别在于,虚引用必须配合引用队列使用。主要配合ByteBuffer使用,当被引用对象被回收时,会将虚引用入队,由Reference Handler线程调用虚引用相关方法释放直接内存。
- 终结器引用:无需手动编码,但其内部配合引用队列使用。在垃圾回收时,终结器引用入队(被引用对象暂时没有被回收),再由Finalizer线程通过终结器引用找到被引用对象并调用他的finalize方法,第二次GC时才能回收被引用对象。
四、回收算法
1、标记清除算法
两个阶段:第一阶段先标记(根据上述的判断垃圾的算法),第二阶段再清除。优点是速度较片;缺点:会造成内存不连续,容易产生内存碎片。
2、标记整理法
也是先标记(根据上述的判断垃圾的算法),然后再整理,会将占用的内存移动到连续的位置。使剩下未使用的内存连续。整理这个动作涉及到内存的复制,以及地址的修改,所以会消耗一定的时间。
3、复制算法
把内存划分成FROM和TO两个区域,每次垃圾回收会把存活的对象由FROM区复制到TO区,然后会交换FROM和TO区。不会造成内存碎片,但是移动也需要消耗一定的时间。而且只能使用一半的内存。
五、分代回收
会将内存分为新生代和老年代,其中新生代又分为伊甸园,FROM区,TO区。当新生代内存空间不足时会发生一次Minor GC,会将伊甸园区存活的对象和FROM区的对象复制到TO区,这些存活的对象的年龄会加1,并交换FROM区和TO区。当一个对象在新生代存活的时间超过某个阈值后,会转移到老年代。
Minor GC会触发一次stop the world,即暂停其它线程,等待垃圾回收线程完成再启用其它线程。(因为垃圾回收涉及到对象的复制、移动)。当老年代空间不足时,会先触发Minor GC,如果之后空间仍然不足时,那么会触发Full GC,这种情况下STW的时间会更长。
六、垃圾回收器
- 串行回收器:是单线程的回收器,适合堆内存比较小的,CPU核数少的个人电脑;若开启串行回收器,在新生代采用的是复制算法;在老年代采用的标记整理法;
串行垃圾回收器主要分为两种:
-
Serial收集器:这是Java虚拟机中最基本、发展历史最悠久的收集器。它是单线程的收集器,只使用一个CPU或一条收集线程去执行垃圾回收。在进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。Serial收集器是客户端模式下的默认新生代收集器。
-
Serial Old收集器:它是Serial收集器的老年代版本,也是单线程的。它同样在垃圾收集过程中需要暂停所有的应用线程。
- 吞吐量优先的回收器:是多核的回收器,适合堆内存较大的,CPU核数多的机器;单位时间内STW的时间少;如0.2 0.2
- 响应时间优先的回收器:是多核的回收器,适合堆内存较大的,CPU核数多的机器;尽可能让单次的STW的时间少;如0.1 0.1 0.1 0.1 0.1