Java垃圾回收手册翻译 - 什么是垃圾回收

初看之下,垃圾回收应该要做其名称之事 - 找到和丢掉垃圾。然而事实上它正好做着相反的事,垃圾回收会记录所有仍在使用中的对象,然后将其他标记为垃圾。谨记这点,我们开始挖掘更多Java虚拟机如何实现被称为垃圾回收的自动化内存回收过程的细节。

为了避免一头扎进细节,我们从头开始,解释垃圾回收的一般性质以及核心概念和方法。

免责声明:本手册关注于Oracle Hotspot和OpenJDK的表现,其他运行时环境甚至其他虚拟机,比如jRockit或IBM J9,会在某些方面有不同于本手册所涵盖的表现。

手动内存管理

在开始现代形式的垃圾回收内容之前,我们先快速回顾一下那些需要手动显示分配和释放数据内存的日子。那时候如果你忘记释放内存,你将不能重用那块内存。这部分内存会被声明到但是没有使用,这种场景叫做内存泄漏

下面是一个用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++中的向量vector做上一个例子中同样的事,它会在离开其作用域时自动的调用其析构函数:

int send_request() {
size_t n = read_size();
vector<int> elements = vector<int>(n); if(read_elements(elements.size(), &elements[0]) < n) {
return -1;
} return 0;
}

但是再更复杂的情况中,尤其是在多个线程中共享对象时,仅仅使用析构函数并不够。这就引出了垃圾回收最简单的形式:引用计数。对每个对象,你只需要知道它有多少次被引用到,并且当这个计数达到零时这个对象就可以安全的被回收。一个众所周知的例子是C++中的共享指针shared pointers

int send_request() {
size_t n = read_size();
auto elements = make_shared<vector<int>>(); // read elements store_in_cache(elements); // process elements further return 0;
}

现在,为了避免下次函数调用时再去读这个元素elements,我们可能想要缓存他们。在这个例子中,就不能再当向量vector离开作用域时销毁它。因此,我们使用共享指针shared_ptr,它记录引用到它的数量,当你使用它传值时计数增加,同时当它离开作用域时计数减少。一旦引用的计数降到零,共享指针shared_ptr就会自动地删除下面的向量。

自动化内存管理

在上面的C++代码中,我们仍然要显式地指出我们要何时关心内存管理。但是如果我们能让所有对象都按这种方式运行呢?那将会十分方便,因为开发者不再需要在用完后考虑清理工作。运行时环境会自动知道某些内存不再使用,然后进行清理,也就是自动回收垃圾。最早的垃圾收集器是在1959年为Listp语言创建的,从那时起这项技术才开始不断前进。

引用计数

我们上面演示的C++中共享指针的想法可以应用到所有对象。许多编程语言,比如Perl、Python和PHP都采用了这个方法。下面一张图片可以很好地阐述它:

绿色的云朵表明它们指向的对象仍在被程序员使用。严格的说,它们可能是当前执行方法中的本地变量或静态变量等。这会随着不同的编程语言而不同,所以我们这里先不关注它。

蓝色的圆圈是内存中活着的对象,其中的数字表示它们被引用的次数。最后,灰色的圆圈是没有被明确使用中的对象(那些直接被绿色云朵引用到的)所引用到的对象。这些灰色的对象是就是垃圾,可以被垃圾收集器清理。

这看起来真的很好,不是么?好吧,确实如此,但是整个方法有个巨大的缺陷。它很容易被一些对象形成的分离的循环终结,这些对象都已不在使用范围但是由于循环引用,因此它们的引用计数都不是零。举例来说:

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

有几种办法可以克服这个缺陷,比如使用特殊的'弱引用'或对循环使用单独的算法。前面提到的编程语言-Perl、Python和PHP,都用了一种或另一种方法处理循环,这超出了本手册的范围。相反,我们开始更详细地研究JVM所使用的方法。

标记和清除

首先,JVM对于对象的可达性构成更加具体。与我们之前看到绿色云朵的含糊定义相反,我们有一个非常详细和明确的一组对象,被称为是垃圾回收根源(GC Roots)。

  • 本地变量
  • 活动线程
  • 静态字段
  • JNI引用

JVM用来追踪所有可达(活着)的对象和确保不可达对象使用的内存能被重用的方法被称为标记和清除算法。它由两个步骤构成:

  • 标记阶段 遍历所有可达对象,从垃圾回收根源开始并在本地内存中记录一个所有这些对象的分类账本。
  • 清除阶段 确保不可达对象使用的内存可以在下次内存分配时重用。

JVM中不同的垃圾回收算法,比如并行清扫、并行标记+复制CMS 在实现这些阶段时略有不同,但是从概念上都有着同上述两个步骤相似的过程。

该关方法的一个至关重要的情况是循环不再产生内存泄露:

不太好的方面是情况是应用线程需要在回收发生时暂停,因为如果引用在不停的变化,你将无法真正的计算出引用的数量。这种临时暂停应用程序以便于JVM专心做清理工作的情况被称为停止世界暂停。它们会因很多原因产生,但是垃圾收集是至今最普遍的一个。

Java垃圾回收手册翻译 - 什么是垃圾回收的更多相关文章

  1. java虚拟机学习-JVM调优总结-垃圾回收面临的问题(8)

    如何区分垃圾 上面说到的“引用计数”法,通过统计控制生成对象和删除对象时的引用数来判断.垃圾回收程序收集计数为0的对象即可.但是这种方法无法解决循环引用.所以,后来实现的垃圾判断算法中,都是从程序运行 ...

  2. 【转载】Java性能优化之JVM GC(垃圾回收机制)

    文章来源:https://zhuanlan.zhihu.com/p/25539690 Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我 ...

  3. Java性能优化之JVM GC(垃圾回收机制)

    Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会在任何一种GC算法中发生.st ...

  4. Java内存模型(JMM)以及 垃圾回收机制 小结

    内存模型: 内存模型描述了程序中各个变量(实例域.静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存中取出变量这样的底层细节,对象最终是存储在内存里面的,这点没有错,但是编译 ...

  5. 【深入理解Java虚拟机】自动内存管理机制——垃圾回收机制

      Java与C++之间有一堵有内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来.C/C++程序员既拥有每一个对象的所有权,同时也担负着每一个对象生 ...

  6. 你必须了解的java内存管理机制(四)-垃圾回收

    本文在个人技术博客不同步发布,详情可用力戳 亦可扫描屏幕右侧二维码关注个人公众号,公众号内有个人联系方式,等你来撩... 相关链接(注:文章讲解JVM以Hotspot虚拟机为例,jdk版本为1.8) ...

  7. Java虚拟机详解(三)------垃圾回收

    如果对C++这门语言熟悉的人,再来看Java,就会发现这两者对垃圾(内存)回收的策略有很大的不同. C++:垃圾回收很重要,我们必须要自己来回收!!! Java:垃圾回收很重要,我们必须交给系统来帮我 ...

  8. java面试官最爱问的垃圾回收机制,这位阿里P7大佬分析的属实到位

    前言 JVM 内存模型一共包括三个部分: 堆 ( Java代码可及的 Java堆 和 JVM自身使用的方法区). 栈 ( 服务Java方法的虚拟机栈 和 服务Native方法的本地方法栈 ) 保证程序 ...

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

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

随机推荐

  1. JSON Web Token 是什么?

    免费获得官方JWT手册并深入学习JWT吧! 简介 JSON Web Token(缩写JWT),是一套开放的标准(RFC 7519),它定义了一种紧凑且自URL安全的方式,以JSON对象的方式在各方之间 ...

  2. 爬虫之 cookie , 验证码,模拟登陆,线程

    需求文档的定制 糗事百科的段子内容和作者(xpath的管道符)名称进行爬取,然后存储到mysql中or文本 http://sc.chinaz.com/jianli/free.html爬取简历模板 HT ...

  3. 浅显易懂的前端知识点(二)——HTTP协议基础

    HTTP 协议的初印象: 是基于 TCP/IP 协议的应用层协议,不涉及数据包的传输,主要规定了客户端和服务器之间的通信格式,默认使用 80 端口. 1 HTTP 协议 0.9 版(1991 年) 是 ...

  4. 线程池技术之:ThreadPoolExecutor 源码解析

    java中的所说的线程池,一般都是围绕着 ThreadPoolExecutor 来展开的.其他的实现基本都是基于它,或者模仿它的.所以只要理解 ThreadPoolExecutor, 就相当于完全理解 ...

  5. spring实战第二章小记-装配bean

    时间:2020/02/06 一.思想 1.创建应用对象之间协作关系的行为通常称为装配,这也是依赖注入(DI)的本质. 对于上面这句话的个人理解:当我们在new一个对象时如果传入了别的对象作为参数(这个 ...

  6. jQuery下载所有版本

    下载地址:http://www.jq22.com/jquery-info122

  7. C语言的puts(),gets(),putchar(),getchar()

    其实puts(),gets()属于字符串输入函数. putchar()与getchar()属于字符输入函数. 1.字符函数 #include<stdio.h> int main(){ ch ...

  8. 用tensorflow搭建RNN(LSTM)进行MNIST 手写数字辨识

    用tensorflow搭建RNN(LSTM)进行MNIST 手写数字辨识 循环神经网络RNN相比传统的神经网络在处理序列化数据时更有优势,因为RNN能够将加入上(下)文信息进行考虑.一个简单的RNN如 ...

  9. VMware Workstation 14 Pro 安装 CentOS 7 Linux 虚拟机

    CentOS 7 下载地址:http://isoredirect.centos.org/centos/7/isos/x86_64/ ,选择 CentOS-7-x86_64-DVD-1908.iso : ...

  10. YUM源部署和使用

    1.前言 为什么需要内部yum源呢,有可能是业务内部的服务器对外是不通了,居于一些安全方面的考虑.内部yum源又有什么好处呢,第一,速度快:第二,内网可控,外网有问题也不影响内网包的下载和安装等. 2 ...