博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
什么是垃圾回收
阅读量:5878 次
发布时间:2019-06-19

本文共 2305 字,大约阅读时间需要 7 分钟。

乍一看,垃圾回收所做的事情应当恰如其名——查找并清除垃圾。

其实却恰恰相反。垃圾回收会跟踪全部仍在使用的对象,然后将剩余的对象标记为垃圾。牢记了这点之后,我们再来深入地了解下这个被称为“垃圾回收”的自己主动化内存回收在JVM中究竟是如何实现的。

手动管理内存

在介绍现代版的垃圾回收之前,我们先来简单地回想下须要手动地显式分配及释放内存的那些日子。假设你忘了去释放内存,那么这块内存就无法重用了。这块内存被占有了却没被使用。

这样的场景被称之为内存泄露。

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

能够看到,你非常easy就会忘了释放内存。内存泄露以前是个非常普遍的问题。你仅仅能通过不断地修复自己的代码来与它们进行抗争。

因此,须要有一种更优雅的方式来自己主动释放无用内存。以便降低人为错误的可能性。这样的自己主动化过程又被称为垃圾回收(简称GC)。

智能指针

自己主动垃圾回收早期的一种实现便是引用计数

你知晓每个对象被引用了几次,当计数器归0的时候,这个对象就能够被安全地回收掉了。C++的共享指针就是一个非常著名的样例:

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

我们使用的shared_ptr会记录这个对象被引用的次数。假设你将它传递给别人则计数加一,当它离开了作用域后便会减一。一旦这个计数为0shared_ptr会自己主动地删除底层相应的vector

当然这仅仅是个演示样例,由于也有读者指出来了。这个在现实中是不太可能出现的,但作为演示是足够了。

自己主动内存管理

在上面的C++代码中。我们还得显式地声明我们须要使用内存管理。那假设全部的对象都採用这个机制会如何呢?那简直就太方便了。这样开发者便无需考虑清理内存的事情了。执行时会自己主动知晓哪些内存不再使用了,然后释放掉它。也就是说,它自己主动地回收了这些垃圾。

第一代的垃圾回收器是1959Lisp引入的,这项技术迄今为止一直在不断演进。

引用计数

刚才我们用C++的共享指针所演示的想法能够应用到全部的对象上来。很多语言比方说Perl, Python以及PHP,採用的都是这样的方式。

这个通过一张图能够非常easy说明:

绿色的云代表的是程序中仍在使用的对象。从技术层面上来说。这有点像是正在执行的某个方法里面的局部变量,亦或是静态变量之类的。不同编程语言的情况可能会不一样。因此这并非我们关注的重点。

蓝色的圆圈代表的是内存中的对象,能够看到有多少对象引用了它们。灰色圆圈的对象是已经没有不论什么人引用的了。因此,它们属于垃圾对象,能够被垃圾回收器清理掉。

看起来还不错对吧?没错,只是这里存在着一个重大的缺陷。非常easy会出现一些孤立的环。它们中的对象都不在不论什么域内。但彼此却互相引用导致引用数不为0。以下便是一个样例:

看到了吧,红色部分其实就是应用程序不再使用的垃圾对象。由于引用计数的缺陷。因此会存在内存泄露。

有几种方法能够解决这一问题。比方说使用特殊的“弱”引用。或者使用一个特殊的算法回收循环引用。

之前提到的Perl,Python以及PHP等语言,都是使用相似的方法来回收循环引用的,只是这已经超出本文讲述的范围了。我们准备具体介绍下JVM所採用的方法。

标记删除

首先,JVM对于对象可达性的定义要明白一些。它可不像前面那样用绿色的云便含糊了事的,而是有着非常明白及具体的垃圾回收根对象(Garbage Collection Roots)的定义:

  • 局部变量
  • 活动线程
  • 静态字段
  • JNI引用
  • 其他(后面将会讨论到)

JVM通过标记删除的算法来记录全部可达(存活)对象,同一时候确保不可达对象的那些内存能够被重用。这包括两个步骤:

  1. 标记是指遍历全部可达对象。然后在本地内存中记录这些对象的信息
  2. 删除会确保不可达对象的内存地址能够在下一次内存分配中使用。

JVM中的不同GC算法。比方说Parallel ScavengeParallel Mark+CopyCMS都是这一算法的不同实现,仅仅是各阶段略有不同而已。从概念上来讲仍然是相应着上面所说的那两个步骤。

这样的实现最重要的就是不会再出现泄露的对象环了:

缺点就是应用程序的线程须要被暂停才干完毕回收。假设引用一直在变的话你是无法进行计数的。这个应用程序被暂停以便JVM能够收拾家务的情况又被称为Stop The World pause(STW)。这样的暂停被触发的可能性有非常多。只是垃圾回收应该是最常见的一种。

转载地址:http://rjdix.baihongyu.com/

你可能感兴趣的文章
《携程的技术演进之路》读后感
查看>>
IE8正式版引发VS2005和VS2008添加变量向导出错的解决方案
查看>>
[BZOJ 2243][SDOI2011] 染色
查看>>
Visual Studio 2010中文旗舰版+大家所关心的
查看>>
LeetCode-78-Subset
查看>>
libtiff.so.3
查看>>
人生感悟
查看>>
CSS transitions深入理解
查看>>
KDTree 板子
查看>>
.NET深入解析LINQ框架2
查看>>
股票新闻速递 隐私声明
查看>>
获取synchronized锁中的阻塞队列中的线程是非公平的
查看>>
在浏览器中输入Google.com并且按下回车之后发生了什么?[转]
查看>>
js刷新页面方法
查看>>
java递归理解
查看>>
工业大数据分析平台的应用价值探讨
查看>>
使用maven引入slf4j、logback时发生冲突
查看>>
课堂作业之找小水王
查看>>
团队编程需求分析
查看>>
Repost: Move semantics and smart pointers by Alex --- learncpp
查看>>