老師的例子不是很好,因爲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");
}
嘆氣,高中教師。 –
建立在別人說的基礎上,垃圾收集在堆上運行,而不是堆棧。堆棧如果存在「範圍」數據,即方法調用中的局部變量。這使得遞歸成爲可能,並且不需要垃圾回收。堆是你的對象和他們的領域中的數據將存活的地方。 –