Java对象可以被垃圾回收器回收的时机是在对象不再被引用时。当一个对象没有任何引用指向它时,垃圾回收器会将其标记为可回收状态。垃圾回收器会定期运行,检查并回收不再被引用的对象的内存空间,释放资源并提供新的空间供程序使用。
Java中的对象由垃圾回收器来负责回收。垃圾回收器通过判断对象的可达性来决定哪些对象可以被回收。
引用计数法: 引用计数法是一种简单的垃圾回收算法。每当对象被引用时,计数器加1;每当对象的引用失效时,计数器减1。当计数器为0时,表示对象没有被引用,可以被回收。引用计数法的优点是实时性好,即对象在失去引用后能够立即被回收。但是引用计数法有一个致命的问题,即循环引用。当两个或多个对象之间相互引用时,计数器永远不会为0,导致内存泄露。
可达性分析算法: 可达性分析算法是Java中主要采用的垃圾回收算法。这个算法基于的思想是通过一系列称为"GC Roots"的根对象作为起点,从这些根对象开始遍历所有对象的引用链,可达的对象被视为存活对象,不可达的对象被视为垃圾对象。垃圾对象会被回收,存活对象会被保留。
GC Roots包括以下几种情况:
可达性分析算法的优点是能够检测到循环引用,并解决循环引用导致的内存泄露问题。它可以准确地确定哪些对象是垃圾,哪些对象是存活的。但是可达性分析算法需要遍历对象图,对于大规模的对象图可能会导致较长的停顿时间。
综上所述,Java中的垃圾回收器主要通过可达性分析算法来确定哪些对象是垃圾。引用计数法虽然简单,但由于无法解决循环引用问题,所以在Java中并不使用。可达性分析算法可以准确地确定对象是否可达,进而决定是否进行回收,具有更好的回收效率和内存管理能力。
标记-清除(Mark and Sweep)算法:该算法首先标记所有活动对象,然后清除所有未标记的对象。这种算法会造成内存碎片,并且清除过程会暂停程序的执行。 举例说明:假设有一块内存区域,其中有多个对象,其中只有几个对象是活动的,标记-清除算法会首先遍历所有对象,将活动对象标记为活动状态,然后清除所有未标记的对象,即将非活动对象所占用的内存释放。
复制算法(Copying):该算法将内存分为两个区域,分别为From区和To区。当From区域中的对象被标记为活动状态后,将这些对象复制到To区域,然后清除From区域中的所有对象。该算法不会产生内存碎片,并且清除过程也很快,但是需要将活动对象从一个区域复制到另一个区域。 举例说明:假设有一块内存区域,其中有多个对象,复制算法会将内存分为From区和To区,首先将所有活动对象从From区复制到To区,然后清除From区中的所有对象。
标记-整理(Mark and Compact)算法:该算法首先标记所有活动对象,然后将它们向一端移动,然后清除移动后的其它对象。这种算法会产生内存碎片,但是清除过程不会暂停程序的执行。 举例说明:假设有一块内存区域,其中有多个对象,标记-整理算法会首先遍历所有对象,将活动对象标记为活动状态,然后将活动对象向一端移动,最后清除移动后的其它对象。
分代回收算法(Generational):该算法将内存分为几个代(Generation),一般情况下将内存分为老年代、新生代和永久代。新生代中的对象生命周期较短,老年代中的对象生命周期较长。分代回收算法会根据代的不同采用不同的回收算法,以提高垃圾回收的效率。 举例说明:假设有一块内存区域,其中有多个对象,分代回收算法会将内存分为老年代和新生代,新生代中的对象生命周期较短,一般采用复制算法;老年代中的对象生命周期较长,一般采用标记-清除或标记-整理算法。
Minor GC(新生代GC):Minor GC是一种垃圾回收算法,它主要用于清理年轻代(Young Generation)中的垃圾对象。年轻代是Java堆内存中的一部分,用于存放新创建的对象。Minor GC的目标是尽快回收年轻代中的垃圾对象,以便为新的对象分配空间。它使用复制算法来进行垃圾回收,即把存活的对象复制到一个新的空间中,然后清理原空间中的所有对象。
Mixed GC(混合GC):Mixed GC是一种综合了Minor GC和Full GC的垃圾回收算法。它主要用于清理整个堆内存中的部分垃圾对象。Mixed GC通常在年轻代GC之后执行,它会查找堆内存中的一些垃圾对象,并进行清理。由于Mixed GC只清理部分堆内存中的对象,因此它的速度相对于Full GC要快一些。
Full GC(全GC):Full GC是一种垃圾回收算法,它用于清理整个Java堆内存中的所有垃圾对象。Full GC会扫描整个堆内存,包括年轻代和老年代(Old Generation),并清理其中的无用对象。Full GC的执行时间相对较长,因为它需要遍历整个堆内存。Full GC通常会触发一次STW(Stop-The-World)暂停,即整个应用程序停止响应,以便进行垃圾回收操作。
总结:
Serial Collector(串行回收器):
Parallel Collector(并行回收器):
CMS (Concurrent Mark-Sweep) Collector(并发标记-清除回收器):
G1 (Garbage-First) Collector(垃圾优先回收器):jdk9之后默认为G1? ? ? ? ?
? ? ? ? ?G1(Garbage-First)垃圾回收器是一种面向服务器应用的垃圾回收器,最早在JDK 7u4版本中引入。它的主要目标是提供高吞吐量和低延迟的垃圾回收能力,并且能够有效地管理大内存堆。
? ? ? ? G1垃圾回收器的工作原理如下:
新生代回收是指对年轻代进行垃圾回收的过程。G1将年轻代分为多个大小相等的区域,当区域满时,会触发一次Minor GC。Minor GC首先会进行一次暂停,停止应用程序的执行,然后将存活的对象复制到空闲的区域中,并且会根据对象的存活时间调整对象的年龄。通过复制算法,Minor GC能够高效地回收年轻代的垃圾。
并发标记是指在并发执行应用程序的同时,对老年代进行垃圾回收的过程。在并发标记过程中,G1会遍历老年代中的对象,并标记出存活的对象。由于并发执行,所以这个阶段不会停顿应用程序的执行。
混合收集是指在并发标记完成后,对整个堆进行垃圾回收的过程。混合收集会选取垃圾最多的区域进行回收,也就是"Garbage-First"的策略。在混合收集过程中,G1会对垃圾最多的区域进行清理,并将存活的对象复制到其他空闲区域。混合收集的目标是在尽量短的停顿时间内回收尽量多的垃圾。
强引用(Strong Reference): 强引用是最常见的引用类型,也是默认的引用类型。当一个对象具有强引用时,即使内存空间不足,垃圾回收器也不会回收它。只有当没有任何强引用指向对象时,垃圾回收器才会将其回收。
示例代码:
Object obj = new Object(); // obj是一个强引用
弱引用(Weak Reference): 弱引用是一种比较弱的引用类型。当一个对象只有弱引用指向它时,即使内存空间充足,垃圾回收器也有可能回收它。弱引用通常用于解决内存泄漏的问题,可以在内存不足时,快速释放一些不再需要的对象。
示例代码:
WeakReference<Object> weakRef = new WeakReference<>(new Object());
Object obj = weakRef.get(); // obj是一个弱引用,可以通过get()方法获取弱引用所指向的对象
软引用(Soft Reference): 软引用是一种比较强的引用类型,比弱引用要强一些。当一个对象只有软引用指向它时,在内存空间不足时,垃圾回收器不会立即回收它,而是在内存真正不足时再回收。软引用通常用于实现缓存机制或对象池。
示例代码:
SoftReference<Object> softRef = new SoftReference<>(new Object());
Object obj = softRef.get(); // obj是一个软引用,可以通过get()方法获取软引用所指向的对象
虚引用(Phantom Reference): 虚引用是一种最弱的引用类型,几乎没有引用的功能。虚引用主要用于跟踪对象被垃圾回收器回收的状态,当一个对象只有虚引用指向它时,不管内存空间是否充足,垃圾回收器都会在回收该对象时发送通知。
示例代码:
ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> phantomRef = new PhantomReference<>(new Object(), queue);
Object obj = phantomRef.get(); // obj是一个虚引用,无法通过get()方法获取引用所指向的对象
区别总结: