垃圾回收(Garbage Collection)是Java的自动内存管理机制,它会自动回收不再使用的对象占用的内存空间,从而防止内存泄漏。
Java中的垃圾回收实现原理如下:
- 找出不再使用的对象(垃圾对象)。Java使用引用计数算法来跟踪对象的引用关系,当一个对象的引用数量为0时就认为它是垃圾对象。
- 回收垃圾对象占用的内存空间。通过调用该对象的finalize()方法,然后从内存中移除它。
- 垃圾收集器会在内存不足时启动,所以对象的回收是不确定的。我们无法知道对象会在什么时候被标记为垃圾对象。
Java提供了几种常用的垃圾收集器:
- 串行收集器(Serial Collector):单线程收集器,会暂停所有的用户线程进行回收。
- 并行收集器(Parallel Collector):多线程收集器,也会暂停用户线程,但由多个线程一起进行回收以提高效率。
- CMS收集器(Concurrent Mark Sweep):并发收集器,用户线程和收集器线程同时执行,不需要完全暂停用户线程。
- G1收集器(Garbage First):并发收集器,也可以与用户线程同时执行,分代收集,将堆内存划分为不同的区域然后优先回收那些存活对象较少的区域。
来看一个简单例子:
我们可以编写一个Java程序,使用VisualVM观察垃圾收集的过程。
public class GCDemo {
public static void main(String[] args) {
GC.gc(); // 手动触发GC
byte[] buffer = new byte[1024*1024*10]; // 10MB
// 回收堆中剩余可用内存,获取内存使用情况
long used1 = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
buffer = null; // 设置buffer为null,使其成为垃圾对象
// 再次回收并获取内存使用情况
long used2 = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
// 两次内存使用之间的差值即为回收的垃圾对象占用的内存
long gcSize = used1 - used2;
System.out.println("GC freed " + gcSize + " bytes.");
}
}
我们可以观察到:
- 手动调用GC后,buffer对象仍然存活,内存使用没有变化。
- 将buffer置为null后,buffer对象成为垃圾对象。
- 第二次GC后,内存使用减少了10MB,这是buffer对象占用的内存被回收了。