什么是垃圾回收?

以下是我们的垃圾收集手册中的一个示例,该手册将在接下来的几周内发布。 同时,花点时间熟悉垃圾收集的基础知识-这将是本书的第一章。

乍一看,垃圾收集应该处理顾名思义的问题-查找并丢弃垃圾。 实际上,它所做的恰恰相反。 垃圾收集正在跟踪所有仍在使用的对象,并将其余对象标记为垃圾。 牢记这一点,我们开始深入研究如何为Java虚拟机实现称为“垃圾回收”的自动内存回收过程。

手动内存管理

在我们开始以现代形式介绍Garbage Collection之前,让我们快速回顾一下您不得不手动和显式分配和释放数据存储空间的日子。 而且,如果您忘记释放它,则将无法重用该内存。 该内存将被声明但未被使用。 这种情况称为内存泄漏

这是一个使用C语言编写的,使用手动内存管理的简单示例:

int send_request() {
    size_t n = read_size();
    int *elements = malloc(n * sizeof(int));

    if(read_elements(n, elements) < n) {
        // elements not freed!
        return -1;
    }

    // …

    free(elements)
    return 0;
}

如我们所见,忘记释放内存是很容易的。 内存泄漏曾经是比现在更常见的问题。 您只能通过修复代码来真正打败他们。 因此,更好的方法将是自动回收未使用的内存,从而完全消除人为错误的可能性。 这种自动化称为垃圾收集 (或简称GC)。

智能指针

自动进行垃圾收集的第一种方法是基于引用计数。 对于每个对象,您只需知道它被引用了多少次,并且当计数达到零时,就可以安全地回收该对象。 一个著名的例子就是C ++的共享指针:

int send_request() {
    size_t n = read_size();
    stared_ptr<vector<int>> elements 
              = make_shared(new vector<int>());

    if(read_elements(n, elements) < n) {
        return -1;
    }

    return 0;
}

我们正在使用的shared_ptr会跟踪对其的引用数。 此数字随着您的传递而增加,而随着其离开范围而减小。 一旦引用数达到零, shared_ptr就会自动删除基础向量。

自动内存管理

在上面的C ++代码中,我们仍然必须明确地说出何时需要进行内存管理。 但是,如果我们可以使所有对象以这种方式表现呢? 这将非常方便,因为开发人员可能不再需要考虑自己清理。 运行时将自动了解不再使用某些内存,并将其释放。 换句话说,它会自动收集垃圾 。 1959年,第一个垃圾收集器出现在Lisp那里,从那时起,这项技术才发展起来。

参考计数

我们用C ++的共享指针演示的想法可以应用于所有对象。 许多语言(例如Perl,Python或PHP)都采用这种方法。 最好用图片说明:

Java GC计数参考1

绿云表示程序员指向的对象仍在使用中。 从技术上讲,这些可能是诸如当前执行的方法中的局部变量或静态变量之类的东西。 它可能因编程语言而异,因此在此我们将不再关注。

蓝色圆圈是内存中的对象,您可以看到对其的引用数量。 最后,灰色圆圈是未从任何范围引用的对象。 因此,灰色物体是垃圾,可以由垃圾收集器清理。

这一切看起来真的很好,不是吗? 可以,但是整个方法都有很大的缺点。 结束对象的分离循环是很容易的,这些对象都不在范围内,但是由于循环引用,其引用的计数不为零。 这是一个例子:

Java GC标记和扫描

看到? 红色对象实际上是应用程序不使用的垃圾。 但是由于引用计数的限制,仍然存在内存泄漏。

有一些方法可以解决此问题,例如使用特殊的“弱”引用或应用单独的算法来收集周期。 提到的语言(Perl,Python和PHP)都以一种或另一种方式处理循环,但这超出了本手册的范围。 相反,我们将开始更详细地研究JVM所采用的方法。

扫一扫

首先,JVM更具体地说明了对象的可访问性。 与其在前几章中看到的模糊定义的绿色云,不如我们有一组非常具体和明确的对象,称为“ 垃圾收集根”

  • 局部变量
  • 活动线程
  • 静态场
  • JNI参考
  • 其他(稍后将讨论)

JVM用于跟踪所有可到达(活动)对象并确保非可到达对象声明的内存可重复使用的方法称为标记和清除算法。 它包括两个步骤:

  • 标记正在遍历所有可到达的对象,并将有关所有此类对象的分类帐保存在本机内存中
  • 扫描确保了不可访问对象占用的内存地址可以在下一次分配中重用。

JVM中的不同GC算法(例如Parallel Scavenge,Parallel Mark + Copy或CMS)在实现这些阶段时稍有不同,但是从概念上讲,该过程仍然类似于上述两个步骤。

关于此方法,至关重要的一点是周期不再泄漏:

Java GC计数参考1

不好的是,需要停止应用程序线程才能进行收集,因为如果引用一直在变化,那么您就无法真正计数引用。 当应用程序暂时停止以使JVM可以沉迷于家政活动时,这种情况称为Stop The World暂停 。 它们的发生可能有多种原因,但是垃圾收集是迄今为止最受欢迎的一种。

如果您能够通过发布获得成功,那么我只能建议订阅我们的Twitter feed ,在其中继续发布与Java性能相关的其他主题。

翻译自: https://www.javacodegeeks.com/2015/05/what-is-garbage-collection.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
垃圾回收是指对于不再使用的内存空间进行自动的回收和释放,以便其他程序使用。在大多数现代编程语言中,程序员不必自己手动管理内存,而是由垃圾回收机制来完成。 常见的垃圾回收算法包括: 1. 标记-清除算法(Mark and Sweep):标记-清除算法通过标记所有可达对象,然后清除未被标记的对象来回收内存。 2. 引用计数算法(Reference Counting):引用计数算法通过跟踪每个对象的引用计数来回收内存。当一个对象的引用计数变为零时,它就可以被回收。 3. 复制算法(Copying):复制算法将内存空间分为两个区域,每次只使用其中一个区域。当一个区域满了之后,将存活的对象复制到另一个区域中,然后清空原来的区域,使其可用于下一次分配。 4. 标记-压缩算法(Mark and Compact):标记-压缩算法通过标记所有可达对象,然后将存活的对象移动到一端,然后清除剩余的内存空间,使其可用于下一次分配。 这些算法的不同之处在于它们的实现方式、效率和适用场景。例如,复制算法在处理大量短暂对象时效率较高,而标记-清除算法则适用于处理大量不同大小的对象。同时,不同的垃圾回收算法也有各自的缺点,例如引用计数算法可能会出现循环引用导致内存泄漏。因此,选择合适的垃圾回收算法需要根据具体的应用场景来进行评估和选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值