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


103

我是Java新手,对Java中的垃圾收集器感到困惑。它实际上是做什么的,什么时候生效。请描述Java中垃圾收集器的一些属性。



10
有时最好阅读一本好书中的一章,以期从一个问题的答案理解一个复杂的主题。
伊恩·林罗斯

4
@Ian这是一个类似的问题,但并非重复。而这个问题恶臭功课。
NullUserException 2010年

Answers:


119

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

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

for (File f : files) {
    String s = f.getName();
}

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

回到代码,我们可以看到,一旦执行了一次迭代,在下一次迭代中,String就不再使用在上一次迭代中创建的对象,该对象现在被视为“垃圾”。

最终,我们将开始产生大量垃圾,内存将用于不再使用的对象。如果这种情况持续下去,最终Java虚拟机将耗尽空间以创建新对象。

那就是垃圾收集器介入的地方。

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

在Java中,垃圾收集器负责内存管理,但是在其他语言(例如C)中,则需要使用诸如malloc和的free功能自行执行内存管理。内存管理是容易出错的事情之一,可能会导致所谓的内存泄漏 -在不再使用内存时无法回收内存的地方。

像垃圾回收这样的自动内存管理方案使程序员不必担心内存管理问题,因此他或她可以将更多精力放在开发他们需要开发的应用程序上。


如果说在计算机上运行的Java应用程序具有两个垃圾收集功能,那是真的吗?一台带有Java虚拟机。然后在运行Windows的实际计算机上安装一个?(或其他任何操作系统)
Lealo

不,通常只有在存在JRE的情况下,Java应用程序才能运行。因此,仅需要JVM的垃圾回收功能!@Lealo
Am_I_Helpful

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 ...  
}

我知道这是非常人为的,但是在您致电之后 otherMethod()原始Object创建将变得无法访问-这就是“垃圾”,它会收集垃圾。

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

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


1
AFAIK System.gc()不会强制GC运行。
Itay Karo 2010年

1
+1为好代码示例。请注意,GC myObj在调用otherMethod发生之前销毁是完全有效的,因为myObj这时不再可用。
Billy ONeal 2010年

@意大利我认为这是特定于实现的。
NullUserException 2010年

2
我相信不应该打电话System.gc(),拥有GC的全部意义就是不必这样做。
Pascal Thivent 2010年

使用转义分析(en.wikipedia.org/wiki/Escape_analysis),在此示例中,JVM甚至可能根本没有分配对象。从理论上讲,可以优化整个对象的创建。当然取决于实现。
mikera

15

如果无法通过任何活动线程或任何静态引用访问对象,则该对象将具有垃圾回收或GC的资格。

换句话说,如果对象的所有引用均为null,则可以说该对象可以进行垃圾回收。循环依赖项不算作引用,因此,如果对象A对对象B的引用,对象B对对象A的引用,并且它们没有任何其他实时引用,则对象A和B都可以进行垃圾回收。


用于垃圾收集的堆世代-

为了在Java中进行垃圾回收,在其中创建Java对象Heap并将Heap其分为三个部分或三代,它们分别称为堆的Young(新)代,Tenured(旧)代和Perm Area

Java堆空间 新一代又分为三个部分,分别称为伊甸园空间,幸存者1和幸存者2空间。当一个对象首先在堆中创建时,它的生成在伊甸园空间内的新一代中进行了,随后在如果一个对象幸存的情况下进行了次要的垃圾收集,它的对象被转移到幸存者1,然后转移到幸存者2,直到主要垃圾收集将该对象转移到旧的或终身代

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

用于垃圾收集的堆世代

在这里参考更多:垃圾收集


尽管可以使用System.gc()Runtime.gc()方法发出请求,但不能强制JVM运行垃圾回收。

在java.lang.System中

public static void gc() {
    Runtime.getRuntime().gc();  
}

在java.lang.Runtime中

public native void gc();  // note native  method

标记和扫描算法-

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

以上操作由标记和扫描算法分两个阶段执行:

  1. 标记相
  2. 扫描阶段

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


6

垃圾回收器意味着程序不再需要的对象是“垃圾”,可以丢弃。


6

垃圾收集器是JRE的一部分,可确保未引用的对象从内存中释放出来。
它通常在应用程序内存不足时运行。AFAIK它包含一个图形,该图形表示对象之间的链接,可以释放孤立的对象。
为了节省当前对象的性能,每当GC扫描一个对象并发现仍引用该对象时,其生成计数就增加1(我认为是3或4个最大值),并且首先扫描新生成的对象。 (内存中的对象越短,就越有可能不再需要它),因此并不是每次GC运行时都会扫描所有对象。
阅读以获得更多信息。


@quantumSoup您对此有把握吗?我相信只有在堆填满时才会发生某种垃圾收集(更昂贵的收集)。
Pablo Fernandez 2010年

2
@quantumSoup-取决于JRE的GC实现。在许多情况下,GC 不会一直运行。相反,它会在您的应用由于堆已满而无法分配对象时运行。最近的HotSpot JVM确实包含并行GC,但默认情况下未启用它。
斯蒂芬·C

这个答案过于集中在机制上。问题是“什么是垃圾收集器”,而不是“垃圾收集器如何运行”
Billy ONeal 2010年

@quantum:中和了您的-1,因为:学习,即此页面用于什么,对吗?要学习,您需要犯错误。惩罚错误会使人们无法学习。希望您可以同意这一点。也许您在这里犯了一个错误。
erikbwork 2010年

1
@erikb:按照这种逻辑,永远不会有任何否决票。淘汰投票对于清除相对较差的答案是必要的。OP显然是一个初学者,并且GC的特定内部功能对于所提出的问题并不重要。由于此答案不能回答所提出的问题(它回答的是其他问题),因此,完全赞成投票。
Billy ONeal 2010年


3

许多人认为垃圾收集会收集和丢弃死掉的物体。
实际上,Java垃圾回收是相反的!跟踪活动对象,并将所有其他内容指定为垃圾。

当不再使用对象时,垃圾回收器将回收底层内存,并将其重新用于将来的对象分配。这意味着没有显式删除,也没有内存返回给操作系统。为了确定不再使用哪些对象,JVM会间歇性地运行非常恰当的标记-清除算法。

检查此以获得更多详细信息:http : //javabook.compuware.com/content/memory/how-garbage-collection-works.aspx


1

用即使是非程序员也能理解的最简单的术语来说,当程序处理数据时,它会为该数据创建中间数据和存储空间(变量,数组,某些对象元数据等)。

当跨功能或以一定大小访问这些对象时,将从中央堆分配它们。然后,当不再需要它们时,需要对其进行清理。

在线上有一些非常好的文章介绍了它是如何工作的,因此我只介绍最基本的定义。

GC基本上是执行此清理的功能。为此,清除所有活动对象未引用的表条目,有效地删除对象,然后复制并压缩内存。比这复杂一点,但是您知道了。

最大的问题是此过程中的某些部分通常需要整个Java VM临时停止才能发生,并且整个过程非常占用处理器和内存带宽。GC的各种选项和每个选项的调整选项旨在在整个GC过程中平衡这些各种问题。


0

Java(以及其他语言/平台)中的垃圾回收是Java运行时环境(JRE)重用不再需要的Java对象中的内存的一种方式。简而言之,当JRE最初启动时,它会要求操作系统(O / S)提供一定数量的内存。当JRE运行您的应用程序时,它将使用该内存。当您的应用程序使用该内存完成后,JRE的“垃圾收集器”就会出现并回收该内存,以供现有应用程序的不同部分使用。JRE的“垃圾收集器”是一个始终在运行的后台任务,它会尝试选择系统空闲时进行垃圾运行的时间。

现实世界中的类比是来到您家并捡起您可回收垃圾的垃圾人……最终,您和/或其他人以其他方式重复使用了这些垃圾。


0

垃圾收集器可以视为参考计数管理器。如果创建了对象并将其引用存储在变量中,则其引用计数将增加一。在执行过程中,如果该变量分配了NULL。该对象的引用计数递减。因此,该对象的当前引用计数为0。现在,当执行垃圾回收器时,它将检查引用计数为0的对象,并释放分配给它的资源。

垃圾收集器调用受垃圾收集策略控制。

您可以在此处获取一些数据。 http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html


1
引用计数是实现GC的一种糟糕方法。我不认为任何主要的JVM实现都使用此方法。
NullUserException 2010年

0

垃圾收集器是jvm的组件。

当cpu免费时,它用于收集垃圾。

这里的垃圾意味着它在主程序的后台运行的未使用的对象

监视主程序的状态。


0

自动垃圾回收是查看堆内存,识别正在使用的对象和未使用的对象以及删除未使用的对象的过程。使用中的对象或引用的对象意味着程序的某些部分仍维护着指向该对象的指针。程序的任何部分都不再引用未使用的对象或未引用的对象。因此,可以回收未引用对象使用的内存。

在像C这样的编程语言中,分配和取消分配内存是手动过程。在Java中,垃圾回收器会自动处理释放内存的过程。请检查链接以获得更好的理解。 http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html


0

垃圾收集是指通过删除程序中不再可访问的对象来自动释放堆上的内存的过程。堆是称为免费存储的内存,代表分配给Java应用程序的大量未使用内存。


1
不要对未引用的文本使用引号格式,如果被引用,则需要引用源。
罗恩侯爵

0

垃圾回收的基本原理是在程序中查找将来无法访问的数据对象,并回收那些对象使用的资源。https://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29

优点

1)从错误中进行保存,即在仍然有指向它的指针的情况下释放了一块内存,并且其中的一个指针被取消引用时发生。 https://en.wikipedia.org/wiki/Dangling_pointer

2)双重释放错误,当程序尝试释放已经释放并且可能已经重新分配的内存区域时,会发生双重释放错误。

3)防止某些类型的内存泄漏,其中程序无法释放已变得无法访问的对象占用的内存,这可能导致内存耗尽。

缺点

1)消耗额外的资源,性能影响,程序执行中可能出现的停顿以及与手动资源管理的不兼容。即使程序员可能已经知道此信息,垃圾回收也会消耗计算资源来确定要释放的内存。

2)实际收集垃圾的时间可能是不可预测的,从而导致在整个会话中分散出现停顿(暂停移位/释放内存)。在实时环境,事务处理或交互式程序中,无法预测的停顿可能是不可接受的。


Oracle教程 http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

垃圾收集是识别哪些对象正在使用,哪些没有使用并删除未使用的对象的过程。

在像C,C ++这样的编程语言中,分配和释放内存是一个手动过程。

int * array = new int[size];
processArray(array); //do some work.
delete array; //Free memory

该过程的第一步称为标记。垃圾收集器在此处确定正在使用哪些内存,哪些内存未使用。

步骤2a。正常删除会删除未引用的对象,而将引用的对象和指针留给可用空间。

为了提高性能,我们希望删除未引用的对象,并压缩其余的引用对象。我们希望将引用的对象保持在一起,因此分配新内存将更快。

如前所述,必须标记和压缩JVM中的所有对象效率很低。随着分配的对象越来越多,对象列表越来越多,导致垃圾收集时间越来越长。

继续阅读本教程,您将知道GC如何应对这一挑战。

简而言之,堆有三个区域,YoungGeneration用于短期对象,OldGeneration用于长期对象,PermanentGeneration用于应用程序生命周期中的对象,例如类,库。


0

当对象由操作员动态分配时,您可以询问如何销毁这些对象以及如何释放繁忙的内存。在其他语言(例如C ++)中,您需要由delete运算符动态释放手动分配的对象。Java有不同的方法。它会自动处理释放。该技术称为垃圾收集

它的工作原理是:当没有对一个对象的引用时,假定不再需要该对象,您可以检索该对象占用的内存。不必像C ++中那样显式销毁对象。垃圾收集在程序执行过程中偶尔发生。这不仅仅因为存在一个或多个不再使用的对象而发生。另外,几种Java运行时实现对垃圾回收使用不同的方法,但是大多数程序员在编写程序时不必担心这一点。


-2

自动垃圾收集是一个过程,在该过程中,JVM摆脱了某些数据点或将某些数据点保留在内存中,从而最终释放了正在运行的程序的空间。内存首先发送到堆内存,这是垃圾收集器(GC)进行工作的位置,然后决定终止或保留该内存。Java假定程序员不能总是被信任,因此它终止了它认为不需要的项目。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.