Java垃圾回收之标记清除算法详解
什么是垃圾回收算法
垃圾回收算法是一种自动管理内存的机制,用于自动回收不再使用的内存空间。 Java 中垃圾回收算法主要有标记清除算法、复制算法、标记整理算法和分代收集算法。
标记清除算法
标记清除算法是最简单的一种垃圾回收算法,它分为两个步骤:标记和清除。
标记
标记可以理解为“识别”不再使用的对象,通常从“根对象”开始遍历所有可达对象,将其进行标记表示,这些被标记的对象将会被认为是“可达的”,也就是还在被使用中的对象。
清除
清除可以理解为“回收”不再使用的对象,进入清除阶段的是没有被标记的对象,它们是已经失效了的对象。在此阶段内,没有被标记的垃圾对象将被回收,以便为后续的数据留出更多的空间。
算法解析
标记清除算法的优点是实现简单,可以对非连续的内存进行回收。但是标记清除算法也存在一些问题。标记清除算法会产生大量的内存碎片,如果没有及时进行整理,无法满足程序对大块内存的需求,从而降低程序的执行效率。此外,标记清除算法无法避免“全停顿”问题,即在标记和清除垃圾对象的过程当中,整个程序都需要停止运行,直到整个清除过程完成才能继续执行,因此标记清除算法不适合对响应时间要求较高的应用程序。
标记清除算法示例
class Student {
String name;
int age;
String major;
}
public class GCExample {
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
s1.name = "Alice";
s1.age = 18;
s1.major = "Computer Science";
s2.name = "Bob";
s2.age = 19;
s2.major = "Mathematics";
s1 = null; //将s1所指向的对象设置为null,使其成为垃圾对象
System.gc(); //显式调用垃圾回收
}
}
在以上示例中,创建了两个 Student
对象 s1
和 s2
,其中 s1 对象被赋值为 null,成为垃圾对象。接着使用 System.gc()
显式调用垃圾回收。
标记清除算法缺陷
使用标记清除算法可能出现的一个问题是内存碎片,即大块的内存区域被分割成小块,程序无法找到足够大的连续内存区域,从而在申请较大的连续内存区域时可能会失败。
public class GCExample2 {
public static void main(String[] args) {
StringBuffer[] sArr = new StringBuffer[1000];
for (int i = 0; i < 1000; i++) {
sArr[i] = new StringBuffer("A");
}
for (int i = 0; i < 900; i++) {
sArr[i] = null;
}
System.gc();
}
}
在以上示例中,创建了一个长度为 1000 的 StringBuffer
数组 sArr
,其中每个 StringBuffer
对象的内容都为单个字符 “A”。接着将前 900 个 StringBuffer
对象设置为 null,成为垃圾对象。接着使用 System.gc()
显式调用垃圾回收。
上面的代码执行后,虽然被清理的内存得到了回收,但是这 900 个 StringBuffer 对象原来所占用的内存却无法被回收。因为这些对象占用的内存不是连续的,而是分散在整个 Java Virtual Machine 的堆内存空间中,无法复用废弃的内存空间。这就导致了程序无法得到足够的连续内存,从而可能在申请较大的连续内存区域时会失败。
结论
虽然标记清除算法是比较简单的垃圾回收算法,但其实际运行的效率和程序可有效使用的内存空间却普遍较低。在实际应用中,需要评估程序的特点和环境以决定是否要使用标记清除算法。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java垃圾回收之标记清除算法详解 - Python技术站