JAVA应用程序开发之GC机制

【本文详细介绍了JAVA应用开发中的GC机制,欢迎读者朋友们阅读、转发和收藏!】

1 基本概念

1.1 什么是 GC 机制?

GC 即垃圾收集机制是指 JVM 用于释放那些不再使用的对象所占用的内存。Java 语言并不要求 JVM 有 GC ,也没有规定 GC 如何工作。不过常用的 JVM 都有 GC ,而且大多数 GC 都使用类似的算法管理内存和执行收集操作。

1.2 GC 常用机制

1.2.1 引用计数

引用计数存储对特定对象的所有引用数,也就是说,当应用程序创建引用以及引用超出范围时, JVM 必须适当增减引用数。当某对象的引用数为 0 时,便可以进行垃圾收集。

1.2.2 对象引用遍历

早期的 JVM 使用引用计数,现在大多数 JVM 采用对象引用遍历。对象引用遍历从一组对象开始,沿着整个对象图上的每条链接,递归确定可到达( reachable )的对象。如果某对象不能从这些根对象的一个(至少一个)到达,则将它作为垃圾收集。在对象遍历阶段, GC 必须记住哪些对象可以到达,以便删除不可到达的对象,这称为标记( marking )对象。

下一步, GC 要删除不可到达的对象。删除时,有些 GC 只是简单的扫描堆栈,删除已标记的对象,并释放它们的内存以生成新的对象,这叫做清除( sweeping )。这种方法的问题在于内存会分成好多小段,而它们不足以用于新的对象,但是组合起来却很大。因此,许多 GC 可以重新组织内存中的对象,并进行压缩( compact ),形成可利用的空间。

为此, GC 需要停止其他的活动。这种方法意味着所有与应用程序相关的工作停止,只有 GC 运行。结果,在响应期间增减了许多混杂请求。另外,更复杂的 GC 不断增加或同时运行以减少或者清除应用程序的中断。有的 GC 使用单线程完成这项工作,有的则采用多线程以增加效率。

1.2.3 标记-清除收集器

这种收集器首先遍历对象图并标记可到达的对象,然后扫描堆栈以寻找未标记对象并释放它们的内存。这种收集器一般使用单线程工作并停止其他操作。

1.2.4 标记-压缩收集器

有时也叫标记-清除-压缩收集器,与标记-清除收集器有相同的标记阶段。在第二阶段,则把标记对象复制到堆栈的新域中以便压缩堆栈。这种收集器也停止其他操作。

1.2.5 复制收集器

这种收集器将堆栈分为两个域,常称为半空间。每次仅使用一半的空间, JVM 生成的新对象则放在另一半空间中。GC 运行时,它把可到达对象复制到另一半空间,从而压缩了堆栈。这种方法适用于短生存期的对象,持续复制长生存期的对象则导致效率降低。

1.2.6 增量收集器

增量收集器把堆栈分为多个域,每次仅从一个域收集垃圾。这会造成较小的应用程序中断。

GC 在 JVM 中通常是由一个或一组进程来实现的,它本身也和用户程序一样占用 heap 空间,运行时也占用 CPU 。当 GC 进程运行时,应用程序停止运行。因此,当 GC 运行时间较长时,用户能够感到 Java 程序的停顿,另外一方面,如果 GC 运行时间太短,则可能对象回收率太低,这意味着还有很多应该回收的对象没有被回收,仍然占用大量内存。因此,在设计 GC 的时候,就必须在停顿时间和回收率之间进行权衡。

一个好的 GC 实现允许用户定义自己所需要的设置,例如有些内存有限的设备,对内存的使用量非常敏感,希望 GC 能够准确的回收内存,它并不在意程序速度的放慢。另外一些实时网络游戏,就不能够允许程序有长时间的中断。增量式 GC就是通过一定的回收算法,把一个长时间的中断,划分为很多个小的中断,通过这种方式减少 GC 对用户程序的影响。虽然,增量式 GC 在整体性能上可能不如普通 GC 的效率高,但是它能够减少程序的最长停顿时间。

Sun JDK 提供的 HotSpot JVM 就能支持增量式 GC 。HotSpot JVM 缺省 GC 方式为不使用增量 GC ,为了启动增量 GC ,我们必须在运行 Java 程序时增加 -Xincgc 的参数。HotSpot JVM 增量式 GC 的实现是采用 Train GC 算法。它的基本想法就是,将堆中的所有对象按照创建和使用情况进行分组(分层),将使用频繁高和具有相关性的对象放在一队中,随着程序的运行,不断对组进行调整。当 GC 运行时,它总是先回收最老的(最近很少访问的)的对象,如果整组都为可回收对象, GC 将整组回收。这样,每次 GC 运行只回收一定比例的不可达对象,保证程序的顺畅运行。

1.2.7 分代收集器

这种收集器把堆栈分为两个或多个域,用以存放不同寿命的对象。JVM 生成的新对象一般放在其中的某个域中。过一段时间,继续存在的对象将获得使用期并转入更长寿命的域中。分代收集器对不同的域使用不同的算法以优化性能。

1.2.8 并发收集器

并发收集器与应用程序同时运行。这些收集器在某点上(比如压缩时)一般都不得不停止其他操作以完成特定的任务,但是因为其他应用程序可进行其他的后台操作,所以中断其他处理的实际时间大大降低。

1.2.9 并行收集器

并行收集器使用某种传统的算法并使用多线程并行的执行它们的工作。在多 CPU 机器上使用多线程技术可以显著的提高 Java 应用程序的可扩展性。

我知道你在看

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200526A0864700?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券