说明:

在本文中, Garbage Collection 翻译为 “垃圾收集”, garbage collector 翻译为 “垃圾收集器”;

一般认为, 垃圾回收 和 垃圾收集 是同义词。

Minor GC 翻译为: 小型GC; 而不是 次要GC

Major GC 翻译为: 大型GC; 而不是 主要GC

原因在于,大部分情况下, 发生在年轻代的 Minor GC 次数会很多,翻译为次要GC明显不对。

Full GC 翻译为: 完全GC; 为了清晰起见,一般直接译为 Full GC,读者明白即可; 其中大型GC和完全GC差不多, 这些术语出自官方的各种分析工具和垃圾收集日志。并不是很统一。

1. 垃圾收集简介

顾名思义,垃圾收集(Garbage Collection)的意思就是 —— 找到垃圾并进行清理。但现有的垃圾收集实现却恰恰相反: 垃圾收集器跟踪所有正在使用的对象,并把其余部分当做垃圾。记住这一点以后, 我们再深入讲解内存自动回收的原理,探究 JVM 中垃圾收集的具体实现, 。

我们不抠细节, 先从基础开始, 介绍垃圾收集的一般特征、核心概念以及实现算法。

免责声明: 本文主要讲解 Oracle Hotspot 和 OpenJDK 的行为。对于其他JVM, 如 jRockit 或者 IBM J9, 在某些方面可能会略有不同。

手动内存管理(Manual Memory Management)

当今的自动垃圾收集算法极为先进, 但我们先来看看什么是手动内存管理。在那个时候, 如果要存储共享数据, 必须显式地进行 内存分配(allocate)和内存释放(free)。如果忘记释放, 则对应的那块内存不能再次使用。内存一直被占着, 却不再使用,这种情况就称为内存泄漏(memory leak)。

以下是用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;
}

可以看到,如果程序很长,或者结构比较复杂, 很可能就会忘记释放内存。内存泄漏曾经是个非常普遍的问题, 而且只能通过修复代码来解决。因此,业界迫切希望有一种更好的办法,来自动回收不再使用的内存,完全消除可能的人为错误。这种自动机制被称为 垃圾收集(Garbage Collection,简称GC)。

智能指针(Smart Pointers)

第一代自动垃圾收集算法, 使用的是引用计数(reference counting)。针对每个对象, 只需要记住被引用的次数, 当引用计数变为0时, 这个对象就可以被安全地回收(reclaimed)了。一个著名的示例是 C++ 的共享指针(shared pointers):

int send_request() {
size_t n = read_size();
shared_ptr<vector<int>> elements
= make_shared<vector<int>>(); if(read_elements(n, elements) < n) {
return -1;
} return 0;
}

shared_ptr 被用来跟踪引用的数量。作为参数传递时这个数字加1, 在离开作用域时这个数字减1。当引用计数变为0时, shared_ptr 自动删除底层的 vector。需要向读者指出的是,这种方式在实际编程中并不常见, 此处仅用于演示。

自动内存管理(Automated Memory Management)

上面的C++代码中,我们要显式地声明什么时候需要进行内存管理。但不能让所有的对象都具备这种特征呢? 那样就太方便了, 开发者不再耗费脑细胞, 去考虑要在何处进行内存清理。运行时环境会自动算出哪些内存不再使用,并将其释放。换句话说, 自动进行收集垃圾。第一款垃圾收集器是1959年为Lisp语言开发的, 此后 Lisp 的垃圾收集技术也一直处于业界领先水平。

引用计数(Reference Counting)

刚刚演示的C++共享指针方式, 可以应用到所有对象。许多语言都采用这种方法, 包括 Perl、Python 和 PHP 等。下图很好地展示了这种方式:

图中绿色的云(GC ROOTS) 表示程序正在使用的对象。从技术上讲, 这些可能是当前正在执行的方法中的局部变量,或者是静态变量一类。在某些编程语言中,可能叫法不太一样,这里不必抠名词。

蓝色的圆圈表示可以引用到的对象, 里面的数字就是引用计数。然后, 灰色的圆圈是各个作用域都不再引用的对象。灰色的对象被认为是垃圾, 随时会被垃圾收集器清理。

看起来很棒, 是吧! 但这种方式有个大坑, 很容易被循环引用(detached cycle) 给搞死。任何作用域中都没有引用指向这些对象,但由于循环引用, 导致引用计数一直大于零。如下图所示:

看到了吗? 红色的对象实际上属于垃圾。但由于引用计数的局限, 所以存在内存泄漏。

当然也有一些办法来应对这种情况, 例如 “弱引用”(‘weak’ references), 或者使用另外的算法来排查循环引用等。前面提到的 Perl、Python 和PHP 等语言, 都使用了某些方式来解决循环引用问题, 但本文不对其进行讨论。下面介绍JVM中使用的垃圾收集方法。

标记-清除(Mark and Sweep)

首先, JVM 明确定义了什么是对象的可达性(reachability)。我们前面所说的绿色云这种只能算是模糊的定义, JVM 中有一类很明确很具体的对象, 称为 垃圾收集根元素(Garbage Collection Roots),包括:

  • 局部变量(Local variables)
  • 活动线程(Active threads)
  • 静态域(Static fields)
  • JNI引用(JNI references)
  • 其他对象(稍后介绍 …)

JVM使用标记-清除算法(Mark and Sweep algorithm), 来跟踪所有的可达对象(即存活对象), 确保所有不可达对象(non-reachable objects)占用的内存都能被重用。其中包含两步:

  • Marking(标记): 遍历所有的可达对象,并在本地内存(native)中分门别类记下。

  • Sweeping(清除): 这一步保证了,不可达对象所占用的内存, 在之后进行内存分配时可以重用。

JVM中包含了多种GC算法, 如Parallel Scavenge(并行清除), Parallel Mark+Copy(并行标记+复制) 以及 CMS, 他们在实现上略有不同, 但理论上都采用了以上两个步骤。

标记清除算法最重要的优势, 就是不再因为循环引用而导致内存泄露:

而不好的地方在于, 垃圾收集过程中, 需要暂停应用程序的所有线程。假如不暂停,则对象间的引用关系会一直不停地发生变化, 那样就没法进行统计了。这种情况叫做 STW停顿(Stop The World pause, 全线暂停), 让应用程序暂时停止,让JVM进行内存清理工作。有很多原因会触发 STW停顿, 其中垃圾收集是最主要的因素。

在本手册中,我们将介绍JVM中垃圾收集的实现原理,以及如何高效地利用GC。

1.【Java GC系列】垃圾收集简介

2.【Java GC系列】JAVA中的垃圾收集

3.【Java GC系列】GC算法(基础篇)

4.【Java GC系列】GC算法(实现篇)

5.【Java GC系列】GC调优(基础篇)

6.【Java GC系列】GC调优(工具篇)

7.【Java GC系列】GC调优(实战篇)

关注码徒公众号,深度学习JAVA!

【Java GC系列】垃圾收集简介(1)的更多相关文章

  1. Java GC系列(4):垃圾回收监视和分析

    本文由 ImportNew - lomoxy 翻译自 javapapers. 目录 垃圾回收介绍 垃圾回收是如何工作的? 垃圾回收的类别 垃圾回收监视和分析 在这个Java GC系列教程中,让我们学习 ...

  2. jvm系列(三):java GC算法 垃圾收集器

    GC算法 垃圾收集器 概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计 ...

  3. Java GC算法 垃圾收集器

    GC算法 垃圾收集器 概述 垃圾收集 Garbage Collection 通常被称为"GC",它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. ...

  4. Java GC系列(1):Java垃圾回收简介

    本文由 ImportNew - 好好先生 翻译自 javapapers. Java的内存分配与回收全部由JVM垃圾回收进程自动完成.与C语言不同,Java开发者不需要自己编写代码实现垃圾回收.这是Ja ...

  5. jvm系列三、java GC算法 垃圾收集器

    原文链接:http://www.cnblogs.com/ityouknow/p/5614961.html 概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 ...

  6. Java GC系列(2):Java垃圾回收是如何工作的?

    本文由 ImportNew - 伍翀 翻译自 javapapers. 目录 垃圾回收介绍 垃圾回收是如何工作的? 垃圾回收的类别 垃圾回收监视和分析 本教程是为了理解基本的Java垃圾回收以及它是如何 ...

  7. Java GC系列(3):垃圾回收器种类

    本文由 ImportNew - 好好先生 翻译自 javapapers. 目录 垃圾回收介绍 垃圾回收是如何工作的? 垃圾回收的类别 垃圾回收监视和分析 在这篇教程中我们将学习几种现有的垃圾回收器.在 ...

  8. Java虚拟机(二):Java GC算法 垃圾收集器

    概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本地方 ...

  9. Java GC系列

    一个国外站点的Java JVM调优系列 下面是国内站点翻译的 http://www.importnew.com/1993.html

随机推荐

  1. Centos-配置网络或显示当前网络接口状态-ifconfig

    ifconfig 配置网络或显示当前网络接口状态,必须由root用户执行 相关选项 -a 显示所有网络接口信息,包括活动或非活动 -s 显示活动接口简要信息 -v 如果网卡接口出现错误则返回错误信息 ...

  2. mysql-7-join

    #进阶7:连接查询 /* 多表连接:查询的字段来自多个表 按功能分类: 内连接: 等值连接 非等值连接 自连接 外连接: 左外连接 右外连接 全外连接 交叉连接 */ USE girls; SELEC ...

  3. LeetCode刷题总结-数学篇

    本文总结LeetCode上有数学类的算法题,推荐刷题总数为40道.具体考点分析如下图: 1.基本运算问题 题号:29. 两数相除,难度中等 题号:166. 分数到小数,难度中等 题号:372. 超级次 ...

  4. LRC 滚动器 + Vue.js

    LRC 滚动展示VueJS cnblogs @ Orcim  最 近一直在学习尤大大的这个前端框架.Vue 无疑是一款极易上手的前端框架,因为官方的文档就是中文的,十分"本土化", ...

  5. 001 01 Android 零基础入门 01 Java基础语法 01 Java初识 01 导学

    001 01 Android 零基础入门 01 Java基础语法 01 Java初识 01 导学 welcome to Java World 欢迎来到Java世界 一起领略Java编程世界的奥秘与奥妙 ...

  6. C\C++中strcat()函数

    转载:https://blog.csdn.net/smf0504/article/details/52055971 C\C++中strcat()函数                           ...

  7. #ifndef, #define, #endif三者的作用

    #ifndef, #define, #endif 作用   #ifndef 它是if not define 的简写,是宏定义的一种,实际上确切的说,这应该是预处理功能三种(宏定义.文件包含.条件编译) ...

  8. 带UI 的小初高数学学习系统 —结对编程项目总结

    一. 项目综述 本系统是基于QT Creator 4.3.0开发环境,开发语言C++,能够实现用户注册,发送短信验证码,用户登陆,用户选择题目类型和数量,显示用户本次答题基本功能.支持对用户账号查重, ...

  9. Linux系统编程—管道

    ▋****1. 管道的概念 管道,又名「无名管理」,或「匿名管道」,管道是一种非常基本,也是使用非常频繁的IPC方式. 1.1 管道本质 管道的本质也是一种文件,不过是伪文件,实际上是一块内核缓冲区, ...

  10. ANOI 2009 【同类分布】

    好累啊啊啊~~~~~~,刷了一天的题了,嗯,再写两篇题解我就去颓Slay... 思路分析: 刚刚我们讲了数位DP,现在就感受一下吧.(其实我也就只敢做做安徽的题,四川的数位DP想都不敢想) 嗯好,我们 ...