文章目录
- 1. Java中对象有哪些引用类型?
- 2. 有哪些基本的垃圾回收算法?
- 3. 什么是分区收集算法?和分代收集什么区别?
- 4. 什么是Minor GC、Major GC、Full GC?
- 5. 什么情况下会触发Full GC?
1. Java中对象有哪些引用类型?
对象有以下几种引用类型:
- 强引用:这是最常见的引用类型。当我们使用关键字new创建一个对象时,会生成一个强引用。只要存在强引用指向一个对象,垃圾收集器就不会回收该对象。
// 创建一个强引用
MyObject obj = new MyObject();
// obj 引用仍然存在,对象不会被垃圾收集器回收
- 软引用:软引用用于描述一些还有用但非必需的对象。当系统内存不足时,垃圾收集器会回收软引用对象。可以通过SoftReference类来创建软引用。
// 创建一个软引用
SoftReference<MyObject> softRef = new SoftReference<>(new MyObject());
// 在内存不足时,垃圾收集器可能会回收软引用对象
MyObject obj = softRef.get();
if (obj == null) {
// 重新创建对象或从其他地方获取对象
}
- 弱引用:弱引用用于描述非必需的对象。如果只存在弱引用指向一个对象,那么垃圾收集器会在下一次运行时回收该对象。可以通过WeakReference类来创建弱引用。
// 创建一个弱引用
WeakReference<MyObject> weakRef = new WeakReference<>(new MyObject());
// 在下一次垃圾收集时,垃圾收集器可能会回收弱引用对象
MyObject obj = weakRef.get();
if (obj == null) {
// 对象已被回收,需要重新创建对象或从其他地方获取对象
}
- 虚引用:虚引用是最弱的引用类型。它的存在主要用于跟踪对象被垃圾收集器回收的活动。虚引用与其他引用类型不同,无法通过虚引用来获取对象,而是通过ReferenceQueue来获取通知。可以通过PhantomReference类来创建虚引用。
// 创建一个虚引用
ReferenceQueue<MyObject> queue = new ReferenceQueue<>();
PhantomReference<MyObject> phantomRef = new PhantomReference<>(new MyObject(), queue);
// 通过 ReferenceQueue 获取通知,并执行相应的操作
Reference<? extends MyObject> ref = queue.poll();
if (ref != null) {
// 执行清理操作或其他逻辑
}
2. 有哪些基本的垃圾回收算法?
-
标记-清除算法(Mark and Sweep):这是最基本的垃圾回收算法。它的过程分为两个阶段:标记阶段和清除阶段。首先,垃圾收集器会从根对象(如栈、静态变量等)开始,通过可达性分析标记出所有活动对象。然后,在清除阶段,垃圾收集器会遍历堆中的所有对象,清除未标记的对象并回收它们所占用的内存。
-
复制算法(Copying):这种算法将堆内存划分为两个大小相等的区域,通常称为"From"区和"To"区。首先,垃圾收集器从根对象开始,将所有活动对象复制到"To"区,同时按顺序紧凑排列,没有被复制的对象就是垃圾。最后,将"From"区和"To"区进行交换,完成垃圾回收。这种算法的优点是简单高效,但内存利用率相对较低。
-
标记-整理算法(Mark and Compact):这种算法结合了标记-清除和复制算法的思想。它首先通过标记阶段标记出所有活动对象,然后将它们向一端移动,紧凑排列,最后清除不可达的对象。相比于复制算法,标记-整理算法避免了内存浪费,但需要额外的移动对象的过程。
-
分代收集算法(Generational Collection):这种算法基于一个观察:大部分对象在短时间内会变得不可达。根据这个观察,分代收集算法将堆内存分为多个代,通常是新生代(Young Generation)和老年代(Old Generation)。
新生代
中的对象通常存活时间较短,使用复制
算法进行回收;老年代
中的对象存活时间较长,使用标记-清除
或标记-整理
算法进行回收。这种算法充分利用了对象存活时间的特点,提高了垃圾回收的效率。
3. 什么是分区收集算法?和分代收集什么区别?
分区收集算法(Partition Collection)是将堆内存划分为不同的区域(partition),每个区域都有自己的垃圾回收方式。常见的分区包括伊甸园区(Eden),幸存者区(Survivor),以及老年代区。
分区收集算法可以根据应用程序的特点和需求,为不同的区域选择最合适的垃圾回收算法。例如,伊甸园区通常使用复制算法,幸存者区可以使用复制算法或标记-整理算法,而老年代区可能使用标记-清除或标记-整理算法。
- 分代收集算法主要关注对象的存活时间,根据存活时间的不同采用不同的回收策略;
- 分区收集算法主要关注堆内存的划分和不同区域的回收方式,每个区域可以选择最适合的垃圾回收算法。
4. 什么是Minor GC、Major GC、Full GC?
- Minor GC(小型垃圾收集):也称为Young GC(新生代垃圾收集),主要针对新生代(Young Generation)进行的垃圾回收过程。新生代通常使用复制算法进行回收。在Minor GC中,垃圾收集器会清理新生代中不再被引用的对象,并将存活的对象复制到另一个区域。Minor GC通常发生频繁,但回收的对象数量较少,所需时间较短。
- Major GC(大型垃圾收集):也称为Old GC(老年代垃圾收集),主要针对老年代(Old Generation)进行的垃圾回收过程。老年代中的对象通常存活时间较长,Major GC会清理老年代中不再被引用的对象。Major GC的触发条件通常包括老年代的空间不足、长时间存活的对象进入老年代等。Major GC通常比Minor GC耗时更长。
- Full GC(完全垃圾收集):也称为Mixed GC(混合垃圾收集),是对整个Java堆(包括新生代和老年代)进行的完整垃圾回收过程。Full GC会清理整个堆内存中的无效对象,包括新生代和老年代中不再被引用的对象。Full GC通常是由特定的条件触发,如堆内存的占用达到阈值、调用System.gc()方法等。Full GC是最耗时的垃圾收集过程,会导致较长的停顿时间。
5. 什么情况下会触发Full GC?
- 显式调用System.gc()
- 老年代空间不足,当老年代的空间不足以容纳新分配的对象时,垃圾收集器会执行Full GC来清理整个堆内存,以释放无效对象并进行内存整理
- 永久代/元空间空间不足,如果永久代空间不足以容纳新的类定义、常量或字符串等,垃圾收集器可能会执行Full GC来释放空间
- 某些分代收集器(如G1垃圾收集器)可能根据具体策略决定执行Full GC