Java垃圾收集 - 它做什么?

时间:2011-10-14 01:33:35

标签: java garbage-collection

我的Java老师(高中课程)正在谈论循环,她说如果你有一个for循环:

for (int i = 0; i < max; i++) {
    //something
}

你不能在循环之外使用变量i,因为垃圾收集功能会删除它,因为它感觉到它是“不需要的”(我知道范围并且这是BS,因为同样的事情发生在所有语言和C ++甚至没有垃圾收集)。现在的问题是......垃圾收集实际上做了什么? (我查了一下,它与堆有关,我还不知道,所以有人向我解释这个)

由于

2 个答案:

答案 0 :(得分:7)

  

(我知道范围,这是BS,因为所有语言都会发生同样的事情,C ++甚至没有垃圾收集)。

正确。由于范围的原因,变量 i不能在循环外使用 - 它与GC没有没有(在潜在的对象可达性之外) )。

  

现在问题是......垃圾收集实际上做了什么? (我查了一下,它与堆有关,我还不知道,所以有人向我解释这个)

垃圾收集器负责回收不再是strongly-reachable 对象。垃圾收集器 nothing [直接]与变量有关,尽管变量可以使对象保持强可达性。 (此外,原始值,例如int 不是对象因此从不由GC处理; - )

我建议您阅读Chapter 9 of Inside the Java Virtual Machine: Garbage CollectionThe Truth About Garbage Collection,因为我相信他们会提供足够的答案/见解和理由。 (垃圾收集wikipedia entry也是一个良好的开端,很好地总结了GC。)

来自“真相”:

  

对象在没有更多强引用存在的情况下进入无法访问状态[强烈可达]。 当一个对象无法访问时,它是收集的候选者注意措辞:仅仅因为一个对象是收集的候选者并不意味着它会被立即收集。 JVM可以自由地延迟收集,直到对象立即需要占用内存为止。

快乐的编码。

答案 1 :(得分:4)

你老师的例子不是很好,因为i可能存储在堆栈上,因为它是一个原语。一个更好的例子是:

public String helloWorld() {
    StringBuilder builder = new StringBuilder();
    builder.append("Hello");
    builder.append(" ");
    builder.append("World!");
    return builder.toString();
}

在函数的第一行,我们分配一个新对象(new StringBuilder())。这个allocates some memory in the heap,后来需要被释放。在C ++中,你最后会做delete builder来处理它(或者在堆栈上分配它 - 但你不能在Java中这样做,所以我认为这是一个合理的例子。)

垃圾收集是一种替代方法,在函数结束时builder没有任何反应。相反,定期地,一个称为垃圾收集器的进程运行,并检查正在使用或未使用的对象,并删除任何不使用的对象。在我给出的示例中,垃圾收集器将运行,注意到无法再访问builder并删除它。

Java的默认垃圾收集器执行称为“标记和扫描”的操作,它基本上遍历它可以访问的所有变量并标记它们(设置了一些标志)。然后删除任何未标记的内容。

我认为在更低的层次上,它实际上做的是移动新内存位置可访问的所有内容,并删除旧内存位置中的任何内容(因为任何内容仍无法访问)。

更简单的垃圾收集方法称为“引用计数”,其中动态分配的所有内容都具有引用计数 - 告诉程序有多少变量指向该内存位置。如果引用计数达到0,则没有人使用该内存,可以立即释放它。上次我检查时,标准Python解释器(CPython)使用它。

引用计数的问题是你可以得到循环:

class Node {
    Node next;
}

public void breakReferenceCountingAlgorithm() {
    Node a = new Node();
    Node b = new Node();
    a.next = b;
    b.next = a;
}

在此函数结束时,a和b都被引用一次(彼此相同),但它们不可访问。无论如何,Java都会捕获它并且垃圾收集它们。 Python不会。


另一方面,你不能在你给出的那个循环之外使用i的原因是作用域,而不是垃圾收集。在函数内部,i的内存可能仍然可用,编译器不允许您访问它。主要是这样你可以这样做:

for(int i = 0; i < 100; i++) {
    System.out.println("stuff");
}

// This i is a different variable
for(int i = 0; i < 100; i++) {
    System.out.println("more stuff");
}