Java之垃圾收集

下面为翻译文章的一定语从句:

原文英文链接:

https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)

https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

来自维基百科:

这篇文章是关于在内存管理中的垃圾收集。有关固态硬盘中的垃圾收集,请参见垃圾收集(SSD)。有关其他用途,请参见垃圾收集(消除歧义)。

在计算机科学中,垃圾收集(GC)是一种自动的内存管理形式。垃圾收集器尝试回收被程序员分配但不再被引用的内训--也称为垃圾。垃圾收集是由美国计算机科学家John McCarthy在1959年发明,目的是简化在Lisp中的手动内存管理。

垃圾收集将程序员从手动内存管理中解脱出来,在手动内存管理中,程序员指定哪些对象被释放并将其返回内存系统中,以及何时释放。其他类似的技术包括堆栈分配、区域推断、内存所有权和多种技术的组合。垃圾回收可能会占用程序总处理时间的很大一部分,因此会对性能产生重大影响。

内存以外的资源,如网络套接字、用户交互窗口、文件和设备描述符通常不由垃圾收集处理。

管理这类资源的方法,特别是析构函数,可能也能管理内存,而不需要GC。有些GC系统允许这样的其他资源与内存区域相关联,当这些区域被收集时,将导致回收这些资源的工作。

原理

垃圾回收的基本原理是找到在程序中将来不被访问的数据对象,回收被这些对象所引用的资源。

许多编程语言需要垃圾回收,无论是作为语言规范的一部分(例如,java、c#、Go和大多数脚本语言),还是用于实际实现(例如,像lambda微积分这样的正式语言),这些被说成是垃圾回收语言。其他语言是被设计成手动内存管理,但是有垃圾收集的实现(例如,C和C++)。一些语言,如Ada、C++,通过对收集的和手动管理的对象使用不同的堆,允许垃圾收集和手动管理在同一个应用程序中共存。其他的,如D,是垃圾收集的,但是允许用户手动删除对象,并且在需要速度时完全禁止垃圾收集。

什么是自动垃圾收集

自动垃圾收集查看堆内存,明确哪些对象在使用和不再使用中,并删除未使用对象的过程。一个在使用或者被引用的对象意味着你程序的某些部分仍然保留了对该对象的引用指针。一个不再使用或者未被引用的对象,不再被你程序的任何部分引用。因此被未引用对象使用的内存可以进行回收。

在像C一类的编程语言中,分配和释放内存是一个手动的过程。在java中,释放内存的过程自动被垃圾收集处理。基本的过程可以如下描述:

步骤1:标记

过程的第一步叫标记。垃圾收集在这里标识哪些内存是在使用中哪些不在使用中。

被引用的对象显示在蓝图中。不被引用的对象显示为金色。在标记阶段所有的对象都会被扫描以做出这一判断。如果系统中所有的对象都被扫描,这会是一个非常耗时的过程。

步骤2:正常删除

正常删除移除未被引用的资源和保留引用的资源和指向空闲空间的指针。

内存分配器保存着对可用空间快的引用,可以在这些快中分配新对象。

步骤2a:压缩性删除

为了进一步提高性能,除了删除未引用的对象外,还可以压缩剩余的引用对象。通过把引用对象合并在一起,会使新内存分配的更容易和更快。

为什么分代垃圾收集

如上所述,对JVM中所有的对象进行标记和压缩是不高效的。随着越来越多的对象被分配,对象列表越来越长导致垃圾收集时间越来越长。然而,应用程序的实证分析表明,大多数对象的寿命都很短。

以下是此类数据的一个示例。Y轴显示分配字节的数量,X轴显示随着时间分配的字节数量。

你可以看到,随着时间的推移,越来越少的对象保留下来。实际上大部分对象有一个短暂的生命,如图左侧的高值所示。

JVM代

从对象分配行为中学到的信息可以用于增强JVM的性能。因此堆被分解成更小的部分或代。堆部分是:年轻代,老年代或终身代,永生代。

年轻一代是所有新对象被分配和老化的地方。当年轻一代填充满了,会引起一个小(minor)的垃圾收集。假设一个很高的对象死亡率,minor垃圾回收可以被优化。年轻一代的死亡对象会被很快的回收。一些保存下来的对象老化了,甚至会被移到老年代。

“停止世界”,所有的minor垃圾收集是停止世界。这意味着所有的应用线程是停止,知道操作完成。Minor垃圾回收肯定会“停止世界”。

老年代被用于储存生命时间长的对象。通常,为年轻代设置一个阈值,当年龄达到要求时,该对象会被移到老年代。最后老年代需要被回收,此事件称为major垃圾收集。

Major垃圾收集同样会“停止世界”。通常一个major垃圾收集会慢的多,因为它涉及所有的活动对象。因此对于响应式应用程序,应当尽量减少major垃圾收集。还要注意,major垃圾收集的“停止世界”的长度受到用于旧代空间的垃圾收集类型的影响。

永生代包含JVM描述应用程序中使用的类和方法所需的元数据。永久代是由JVM在运行时基于应用程序使用的类填充的。此外,Java SEK库类和方法可以储存在这里。

如果JVM发现它们不再被需要或者其他类需要空间,类可能会被回收。永久代包含在一个完整的垃圾收集中。

垃圾收集过程

现在你知道了堆为什么会被分成不同的代,现在是时候看看这些空间是如何交互的了。下面的图片演示了JVM中的对象分配和老化过程。

  1. 首选,任何新的对象都会分配到eden空间。两个幸存空间都是空的。

  2. eden空间填满之后,minor垃圾回收被触发。

  3. 引用的对象被移到第一个幸存空间。未被引用的对象在eden空间被清除的时候被删除。

  4. 在下一次的minor垃圾回收中,eden空间发生同样的事情。未被引用的对象被删除和引用的对象被移动到幸存者空间。然而,在这种情况下,他们被移动到第二个幸存空间(S1)。此外,在第一个幸存空间(S0)中来自上一次minor GC的对象年龄会递增并移到S1中。一旦所有的幸存对象移到了S1中,S0和eden都会被清除。注意,现在在幸存空间中已经有不同年龄的对象。

  5. 在下一次的minor的GC时,相同的处理过程重复进行。然而这一次幸存空间交换。引用的对象从S1中移到S0。幸存对象是老化的,eden和S1被清空。

  6. 这张图片展示的“促销”。一个minor垃圾回收后,当对象的年龄达到一个适当的阈值(在这个实例中是8),它们会被从年轻代“促销”到老年代。

  7. 随着minor GC事件持续发生,对象将会被持续的从年轻代“促销”到老年代空间中去。

  8. 这几乎涵盖了年轻一代的整个过程。最后,将对老年代执行major GC,以清除和压缩该空间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值