我是 Java 新手,对 Java 中的垃圾收集器感到困惑。它实际上做了什么,什么时候开始行动。请描述Java中垃圾收集器的一些属性。
garbage collector 是在 Java Virtual Machine 上运行的程序,它可以清除 Java 应用程序不再使用的对象。它是一种自动内存管理的形式。
当一个典型的 Java 应用程序运行时,它会创建新的对象,例如 String
和 File
,但在一定时间之后,这些对象就不再使用了。例如,看看下面的代码:
for (File f : files) {
String s = f.getName();
}
在上述代码中,String s
是在 for
循环的每次迭代中创建的。这意味着在每次迭代中,都会分配一点内存来创建 String
对象。
回到代码,我们可以看到,一旦执行了一次迭代,在下一次迭代中,在上一次迭代中创建的 String
对象就不再被使用——该对象现在被认为是“垃圾”。
最终,我们将开始获得大量垃圾,并且内存将用于不再使用的对象。如果这种情况持续下去,最终 Java 虚拟机将耗尽空间来创建新对象。
这就是垃圾收集器介入的地方。
垃圾收集器将寻找不再使用的对象,并删除它们,释放内存,以便其他新对象可以使用那块内存。
在 Java 中,内存管理由垃圾收集器负责,但在 C 等其他语言中,需要使用 malloc
and free
等函数自行执行内存管理。 Memory management 是那些容易出错的事情之一,这可能导致所谓的 memory leaks - 不再使用时不会回收内存的地方。
像垃圾收集这样的自动内存管理方案使程序员不必担心内存管理问题,因此他或她可以更多地专注于开发他们需要开发的应用程序。
它释放分配给程序不再使用的对象的内存 - 因此名称为“垃圾”。例如:
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 会自动运行,但您也可以使用 System.gc()
显式调用它并尝试强制进行主要垃圾回收。正如 Pascal Thivent 指出的那样,您真的不应该必须这样做,它可能弊大于利(请参阅 this question)。
有关更多信息,请参阅 Garbage collection 和 Tuning Garbage Collection 上的 wikipedia 条目(来自 Oracle)
System.gc()
不会强制 GC 运行。
otherMethod
之前销毁 myObj
是完全有效的,因为此时无法再访问 myObj
。
System.gc()
,拥有 GC 的全部意义在于不必这样做。
如果无法从任何活动线程或任何静态引用访问对象,则该对象符合垃圾收集或 GC 的条件。
换句话说,如果一个对象的所有引用都为空,则可以说该对象有资格进行垃圾回收。循环依赖不计为引用,因此如果对象 A 引用了对象 B,而对象 B 引用了对象 A,并且它们没有任何其他实时引用,那么对象 A 和 B 都将有资格进行垃圾收集。
垃圾收集的堆代 -
Java 对象在 Heap
中创建,Heap
被分为三部分或三代,以便在 Java 中进行垃圾回收,它们分别称为 Young(New) generation、Tenured(Old) Generation 和堆的 Perm 区域。
https://i.stack.imgur.com/hsFVX.png
Java Heap 的 Perm 空间是 JVM 存储有关类和方法、字符串池和类级别详细信息的元数据的地方。
https://i.stack.imgur.com/seWdT.jpg
请参阅此处了解更多信息:Garbage Collection
尽管您可以使用 System.gc()
或 Runtime.gc()
方法发出请求,但您不能强制 JVM 运行垃圾收集。
public static void gc() {
Runtime.getRuntime().gc();
}
public native void gc(); // note native method
标记和扫描算法 -
这是垃圾收集使用的最流行的算法之一。任何垃圾收集算法都必须执行 2 个基本操作。一,它应该能够检测到所有无法访问的对象,其次,它必须回收垃圾对象使用的堆空间,并使空间再次可供程序使用。
以上操作由 Mark and Sweep Algorithm 分两个阶段进行:
标记阶段 扫描阶段
阅读此处了解更多详情 - Mark and Sweep Algorithm
垃圾收集器意味着程序不再需要的对象是“垃圾”,可以丢弃。
Garbage Collector 是 JRE 的一部分,可确保从内存中释放未引用的对象。
它通常在您的应用程序内存不足时运行。 AFAIK 它拥有一个图,表示对象之间的链接和可以释放的孤立对象。
为了节省性能,将当前对象分组为几代,每次 GC 扫描一个对象并发现它仍然被引用,其生成计数递增1(到某个最大值,我认为是 3 或 4),并且首先扫描新一代(内存中最短的对象越有可能不再需要),因此并非每次 GC 运行时都会扫描所有对象。< br> 阅读 this 了解更多信息。
The garbage collector allows your computer to simulate a computer with infinite memory. 其余的只是机制。
它通过检测何时不再可以从您的代码访问内存块并将这些块返回到空闲存储来实现这一点。
编辑:是的,该链接适用于 C#,但 C# 和 Java 在这方面是相同的。
许多人认为垃圾收集收集和丢弃死对象。实际上,Java 垃圾收集正在做相反的事情!活动对象被跟踪,其他一切都被指定为垃圾。
当不再使用对象时,垃圾收集器会回收底层内存并将其重新用于将来的对象分配。这意味着没有显式删除,也没有将内存返回给操作系统。为了确定哪些对象不再使用,JVM 会间歇性地运行一种非常恰当地称为标记和清除算法的方法。
检查此以获取更多详细信息:http://javabook.compuware.com/content/memory/how-garbage-collection-works.aspx
用最简单的术语来说,即使是非程序员也能理解,当程序处理数据时,它会为该数据创建中间数据和存储空间(变量、数组、某些对象元数据等)。
当跨函数或超过一定大小访问这些对象时,它们是从中央堆分配的。然后当它们不再需要时,需要清理它们。
网上有一些很好的文章介绍了它是如何工作的,所以我只介绍非常基本的定义。
GC 基本上就是执行此清理的函数。这样做是清除没有被任何活动对象引用的表条目,有效地删除对象,而不是复制和压缩内存。它比这更复杂一些,但你明白了。
最大的问题是这个过程的某些部分通常需要整个 Java VM 需要暂时停止才能发生,并且整个过程非常占用处理器和内存带宽。 GC 的各种选项和每个选项的调整选项旨在平衡这些各种问题与整个 GC 过程。
Java(以及其他语言/平台)中的垃圾收集是 Java 运行时环境(JRE)从不再需要的 Java 对象中重用内存的一种方式。简单地说,当 JRE 最初启动时,它会向操作系统 (O/S) 请求一定数量的内存。当 JRE 运行您的应用程序时,它会使用该内存。当您的应用程序使用完该内存后,JRE 的“垃圾收集器”就会出现并回收该内存以供现有应用程序的不同部分使用。 JRE 的“垃圾收集器”是一个始终运行的后台任务,它会尝试在系统空闲时选择时间以继续其垃圾运行。
一个现实世界的类比是垃圾人来到您家并捡起您的可回收垃圾......最终,您和/或其他人以其他方式重复使用这些垃圾。
垃圾收集器可以看作是一个引用计数管理器。如果创建了一个对象并将其引用存储在变量中,则其引用计数增加一。在执行过程中,如果该变量被赋值为 NULL。该对象的引用计数减少。所以对象的当前引用计数为 0。现在,当垃圾收集器执行时,它会检查引用计数为 0 的对象。并释放分配给它的资源。
垃圾收集器调用由垃圾收集策略控制。
你可以在这里得到一些数据。 http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html
垃圾收集器是 jvm 的一个组件。
它用于在 cpu 空闲时收集垃圾。
这里的垃圾是指它在主程序的后台运行的未使用的对象
监控主程序的状态。
自动垃圾回收是查看堆内存,识别哪些对象正在使用,哪些没有,并删除未使用的对象的过程。使用中的对象或引用的对象意味着程序的某些部分仍然维护指向该对象的指针。程序的任何部分都不再引用未使用的对象或未引用的对象。因此可以回收未引用对象使用的内存。
在像 C 这样的编程语言中,分配和释放内存是一个手动过程。在 Java 中,释放内存的过程由垃圾收集器自动处理。请检查链接以获得更好的理解。 http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html
垃圾回收是指通过删除程序中不再可访问的对象来自动释放堆上内存的过程。堆是称为空闲存储的内存,代表分配给 Java 应用程序的大量未使用内存。
垃圾回收的基本原理是在程序中找到以后无法访问的数据对象,并回收这些对象使用的资源。 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 用于在应用程序生命周期中存在的对象,例如类、库。
由于对象是由 new 运算符动态分配的,因此您可以询问这些对象是如何被销毁的以及如何释放繁忙的内存。在 C++ 等其他语言中,您需要通过 delete 运算符动态释放手动分配的对象。 Java 有不同的方法。它会自动处理释放。该技术被称为垃圾收集。
它的工作原理是这样的:当没有对某个对象的引用时,假定不再需要该对象,您可以检索该对象占用的内存。不必像在 C++ 中那样显式地销毁对象。垃圾收集在程序执行过程中偶尔发生;它不会仅仅因为有一个或多个不再使用的对象而发生。此外,几种Java运行时实现有不同的垃圾收集方法,但大多数程序员在编写程序时不必担心这一点。
自动垃圾收集是 JVM 在内存中删除或保留某些数据点以最终为正在运行的程序释放空间的过程。内存首先被发送到堆内存,即垃圾收集器 (GC) 工作的地方,然后决定终止或保留。 Java 假定程序员不能总是被信任,所以它会终止它认为不需要的项目。