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. ios---图片缩放

    1.设置scrollview的代理 2.实现如下方法 -(UIView )viewForZoomingInScrollView:(UIScrollView )scrollView{ return se ...

  2. .net 项目更改默认命名空间

    这个项目是我去年毕业设计做的项目,项目创建的时候由于手抖把Landlordtenant写成了 LandloRdtenant(R大写了),当时不知道如何改回来又担心改完之后报错也就没管了. 今天尝试使用 ...

  3. sys model 常见用法

    import sys #与python解释器 交互 print(sys.argv) #是一个列表 解释器执行文件名后面可以增加字符串 以列表元素形式添加进去def foo(): print('ok') ...

  4. 20190708三人开黑CF模拟赛

    7月8号晚上8点和两位巨佬开了一场虚拟cf: [Helvetic Coding Contest 2018 online mirror (teams allowed, unrated)] 我这么蔡,只A ...

  5. (数据科学学习手札74)基于geopandas的空间数据分析——数据结构篇

    本文对应代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 geopandas是建立在GEOS.GDAL.P ...

  6. Owncloud - Can't write into config directory!

    Owncloud - Can't write into config directory! Can't write into config directory! This can usually be ...

  7. 《ASP.NET Core 高性能系列》静态文件中间件

    一.概述 静态文件(如 HTML.CSS.图片和 JavaScript等文件)是 Web程序直接提供给客户端的直接加载的文件. 较比于程序动态交互的代码而言,其实原理都一样(走Http协议), ASP ...

  8. 自学Java第四章——《数组》

    4.1 数组的相关概念和名词(了解) 1.数组(array): 一组具有相同数据类型的数据的按照一定顺序排列的集合. 把有限的几个相同类型的变量使用一个名称来进行统一管理. 2.数组名: (1)这个数 ...

  9. eclipse编写代码所遇到的问题

    spring方面: 1.Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListabl ...

  10. tmobst5

    (单选题)SQL语言又称为() A)结构化定义语言 B)结构化控制语言 C)结构化查询语言 D)结构化操纵语言 2.(单选题)只有满足联接条件的记录才包含在查询结果中,这种联接为( ) A)左联接 B ...