Java中的垃圾收集器是什么?

Sub*_*hra 101 java garbage-collection

我是Java新手,对Java中的垃圾收集器感到困惑.它实际上做了什么以及什么时候开始行动.请描述Java中垃圾收集器的一些属性.

coo*_*ird 118

垃圾收集器是运行在一个程序的Java虚拟机,其摆脱其未使用的Java应用程序了对象.它是一种自动内存管理的形式.

当典型的Java应用程序正在运行时,它正在创建新对象,例如Strings和Files,但在一定时间之后,这些对象不再使用.例如,看看以下代码:

for (File f : files) {
    String s = f.getName();
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,String s正在循环的每次迭代中创建for.这意味着在每次迭代中,都会分配一点内存来创建一个String对象.

回到代码,我们可以看到,一旦执行了一次迭代,在下一次迭代中,在上一次迭代String中创建的对象不再被使用 - 该对象现在被认为是"垃圾".

最终,我们将开始获得大量垃圾,并且内存将用于不再使用的对象.如果这种情况继续下去,最终Java虚拟机将耗尽空间来创建新对象.

这就是垃圾收集器进入的地方.

垃圾收集器将查找不再使用的对象,并清除它们,释放内存,以便其他新对象可以使用该内存.

在Java中,内存管理由垃圾收集器处理,但在其他语言(如C)中,需要使用诸如malloc和之类的free函数自行执行内存管理.内存管理是易于出错的事情之一,这可能导致所谓的内存泄漏 - 内存在不再使用时无法回收的地方.

像垃圾收集这样的自动内存管理方案使得程序员不必过多担心内存管理问题,因此他或她可以更专注于开发他们需要开发的应用程序.


Nul*_*ion 18

它释放了分配给程序未被程序使用的对象的内存 - 因此名称为"垃圾".例如:

public static Object otherMethod(Object obj) {
    return new Object();
}

public static void main(String[] args) {
    Object myObj = new Object();
    myObj = otherMethod(myObj);
    // ... more code ...  
}
Run Code Online (Sandbox Code Playgroud)

我知道这是非常人为的,但是在你打电话之后otherMethod(),Object创建的原始文件无法访问 - 这就是垃圾收集的"垃圾".

在Java中,GC会自动运行,但您也可以显式调用它System.gc()尝试强制进行主要的垃圾回收.正如Pascal Thivent指出的那样,你真的不应该这样做,它可能弊大于利(见这个问题).

有关更多信息,请参阅有关垃圾收集调整垃圾收集的维基百科条目(来自Oracle)

  • 我相信一个人不应该调用`System.gc()`,有一​​个GC的重点就是不必这样做. (2认同)

roo*_*ler 14

如果无法从任何活动线程或任何静态引用访问对象,则该对象符合垃圾收集或GC的条件.

换句话说,如果对象的所有引用都为null,则可以说对象符合垃圾回收的条件.循环依赖关系不计入引用,因此如果对象A具有对对象B的引用并且对象B具有对对象A的引用并且它们没有任何其他实时引用,则对象A和B都将有资格进行垃圾收集.


垃圾收集的堆生成 -

为了Java中的垃圾收集,Java对象被创建HeapHeap分为三个部分或几代,这些被称为Young(新)生成,Tenured(旧)生成和堆的Perm区域.

Java堆空间 新一代进一步分为三个部分,称为伊甸园空间,幸存者1和幸存者2空间.当一个对象最初在堆中创建时,它在Eden空间内的新一代中被创建,并且在随后的小垃圾收集之后,如果一个对象存活,它将被移动到幸存者1,然后幸存者2在主要垃圾收集之前将该对象移动到旧的或终身生成.

Java Heap的Perm空间是JVM存储有关类和方法,字符串池和类级别详细信息的元数据的位置.

垃圾收集的堆生成

请参阅此处了解更多:垃圾收集


虽然您可以使用System.gc()Runtime.gc()方法发出请求,但您无法强制JVM运行垃圾收集.

在java.lang.System中

public static void gc() {
    Runtime.getRuntime().gc();  
}
Run Code Online (Sandbox Code Playgroud)

在java.lang.Runtime中

public native void gc();  // note native  method
Run Code Online (Sandbox Code Playgroud)

标记和扫描算法 -

这是垃圾收集使用的最流行的算法之一.任何垃圾收集算法都必须执行2个基本操作.一,它应该能够检测所有无法到达的对象;其次,它必须回收垃圾对象使用的堆空间,并使空间再次可用于程序.

上述操作由Mark和Sweep Algorithm分两个阶段执行:

  1. 标记阶段
  2. 扫相

在此处阅读更多详细信息 - 标记和扫描算法


Nik*_*Nik 6

垃圾收集器意味着程序不再需要的对象是"垃圾"并且可以被丢弃.


Ita*_*aro 6

垃圾收集器是JRE的一部分,它确保未引用的对象将从内存中释放.
它通常在应用程序内存不足时运行.AFAIK它拥有一个图形,表示对象和孤立对象之间的链接可以被释放.
为了保存性能,当前对象分组为几代,每次GC扫描一个对象并发现它仍然被引用它的生成计数递增1(到某个最大值最大值,我认为是3或4),并且首先扫描新一代(内存中的对象最短,不再需要它),因此每次GC运行时都不会扫描所有对象.
阅读本文以获取更多信息.

  • @quantumSoup - 这取决于JRE的GC实现.在许多情况下,GC*不会*不断运行.相反,它会在您的应用无法分配对象时运行,因为堆已满.最近的HotSpot JVM确实包含并行GC,但默认情况下不启用它. (2认同)