Java 垃圾收集 - 它有什么作用?
我的 Java 老师(高中课程)正在谈论循环,她说如果你有一个 for
循环,例如:
for (int i = 0; i < max; i++) {
//something
}
你不能在循环之外使用变量 i
因为垃圾收集功能会删除它,因为它感觉到它是“不需要的”(我知道作用域,这是废话,因为所有语言都会发生同样的事情,而 C++ 甚至没有垃圾收集)。现在的问题是……垃圾收集实际上是做什么的? (我查了一下,它与我还不知道的堆有关,所以有人向我解释一下)
谢谢
My Java teacher (High school course) was talking about loops and she said that if you have a for
loop like:
for (int i = 0; i < max; i++) {
//something
}
you can't use the variable i
outside of the loop because the garbage collection feature deletes it because it senses that it's "unneeded" (I know about scopes and that this is BS because the same thing happens in all languages and C++ doesn't even have garbage collection). Now the question is... What does Garbage Collection actually do? (I looked it up and it had something to do with heaps which I don't know about yet so someone explain this to me)
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
正确的。由于作用域的原因,变量
i
不能在循环外部使用 - 它与 GC 没有任何关系(在潜在对象之外)可达能力)。垃圾收集器负责回收不再存在的对象 强可达。尽管变量可以保持对象强可达性,但垃圾收集器与变量没有任何关系。 (此外,原始值,例如
int
不是对象,因此永远不会被 GC 处理;-)我建议通读 《Java 虚拟机内部》第 9 章:
垃圾收集和垃圾收集的真相 因为我相信他们会提供足够的答案/见解和理由。 (垃圾收集 wikipedia 条目 也是一个很好的开始,很好地总结了 GC一般而言。)
来自“真相”:
快乐编码。
Correct. The variable
i
can't be used outside the loop because of scope -- it has nothing to do with the GC (outside of potential object reach-ability).The Garbage Collector is responsible for reclaiming objects which are no longer strongly-reachable. A garbage collector has nothing [directly] to do with variables, although a variable can keep an object strongly-reachable. (Also, primitive values, such as
int
are not objects are thus never dealt with by the GC ;-)I would recommend reading through Chapter 9 of Inside the Java Virtual Machine:
Garbage Collection and The Truth About Garbage Collection as I believe they will provide sufficient answers/insight and justification. (The Garbage Collection wikipedia entry is also a good start and nicely summarizes GC in general.)
From "The Truth":
Happy coding.
您老师的示例不是很好,因为
i
可能存储在堆栈中,因为它是原语。一个更好的例子是:在函数的第一行,我们分配一个新对象(
new StringBuilder()
)。 在堆中分配一些内存,稍后需要释放这些内存。在 C++ 中,您可以在最后执行delete builder
来处理该问题(或在堆栈上分配它 - 但您不能在 Java 中执行此操作,所以我认为这是一个合理的示例)。垃圾收集是一种替代方法,在函数结束时
builder
不会发生任何事情。相反,一个称为垃圾收集器的进程会定期运行,检查哪些对象正在使用或未使用,并清除任何未使用的对象。在我给出的示例中,垃圾收集器将运行,注意到无法再访问builder
,然后将其删除。Java 的默认垃圾收集器执行称为“标记和清除”的操作,它基本上遍历它可以访问的所有变量并标记它们(设置一些标志)。然后它会删除所有未标记的内容。
我认为在更低的层面上,它实际上所做的是将所有可访问的内容移动到新的内存位置,并删除旧内存位置中的所有内容(因为仍然无法访问任何内容)。
一种更简单的垃圾收集方法称为“引用计数”,其中动态分配的所有内容都有一个引用计数——告诉程序有多少变量指向该内存位置。如果引用计数达到 0,则表明没有人正在使用该内存,并且可以立即释放该内存。上次我检查时,标准 Python 解释器(CPython)使用了它。
引用计数的问题在于您可能会出现循环:
在此函数末尾,a 和 b 都被引用一次(彼此),但它们不可访问。无论如何,Java 都会捕捉到这一点并对它们进行垃圾收集。 Python 不会。
另一方面,您不能在给出的循环之外使用
i
的原因是范围界定,而不是垃圾收集。在函数内部,i
的内存可能仍然可用,只是编译器不允许您访问它。主要是这样你可以这样做:Your teacher's example isn't very good, because
i
is probably being stored on the stack since it's a primitive. A better example would be:In the first line of the function we allocate a new object (
new StringBuilder()
). This allocates some memory in the heap, which later needs to be freed. In C++, you'd dodelete builder
at the end to handle that (or allocate it on the stack -- but you can't do that in Java so I think this is a reasonable example).Garbage collection is an alternate method, where nothing happens to
builder
at the end of the function. Instead, periodically, a process called the garbage collector runs, and checks what objects are or aren't in use, and gets rid of anything that's not. In the example I gave, the garbage collector will run, notice that there's no way to accessbuilder
anymore, and delete it.Java's default garbage collector does something called "mark and sweep", where it basically walks through all of the variables it can access and marks them (some flag is set). Then it deletes anything that's not marked.
I think at an even lower level, what it actually does is move everything that's accessible to a new memory location, and delete anything in the old memory location (because anything still there wasn't accessible).
An easier garbage collection method is called "reference counting", where everything that's dynamically allocated has a reference count -- telling the program how many variables are pointed at that memory location. If the reference count ever hits 0, no one is using that memory and it can be immediately freed. Last time I checked, the standard Python interpreter (CPython) uses this.
The problem with reference counting is that you can get loops:
At the end of this function, a and b are both referenced once (by each other), but they're not accessible. Java will catch this and garbage collect them anyway. Python would not.
On another note, the reason you can't use
i
outside of that loop you gave is scoping, not garbage collection. Inside of the function,i
's memory is probably still available, the compiler just won't let you access it. Mainly so you can do this: