文档章节

【JAVA基础知识】Java 垃圾回收机制概念

潭州学院
 潭州学院
发布于 2015/06/08 17:27
字数 1696
阅读 29
收藏 0

    本文,主要介绍关于垃圾回收机制方面的JAVA基础知识。 我们乍一看,垃圾回收所做的事情应当恰如其名——查找并清除垃圾。事实上却恰恰相反。垃圾回收会跟踪所有仍在使用的对象,然后将剩余的对象标记为垃圾。牢记了这点之后,我们再来深入地了解下这个被称为“垃圾回收”的自动化内存回收在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;
}

可以看到,你很容易就会忘了释放内存。内存泄露曾经是个非常普遍的问题。你只能通过不断地修复自己的代码来与它们进行抗争。因此,需要有一种更优雅的方式来自动释放无用内存,以便减少人为错误的可能性。这种自动化过程又被称为垃圾回收(简称GC)。

智能指针

自动垃圾回收早期的一种实现便是引用计数。你知晓每一个对象被引用了几次,当计数器归0的时候,这个对象就可以被安全地回收掉了。C++的共享指针就是一个非常著名的例子:

int send_request() {
    size_t n = read_size();
    stared_ptr<vector<int>> elements 
              = make_shared<vector<int>&gt();

    if(read_elements(n, elements) < n) {
        return -1;
    }

    return 0;
}

我们使用的sharedptr会记录这个对象被引用的次数。如果你将它传递给别人则计数加一,当它离开了作用域后便会减一。一旦这个计数为0,sharedptr会自动地删除底层对应的vector。当然这只是个示例,因为也有读者指出来了,这个在现实中是不太可能出现的,但作为演示是足够了。

自动内存管理

在上面的C++代码中,我们还得显式地声明我们需要使用内存管理。那如果所有的对象都采用这个机制会怎样呢?那简直就太方便了,这样开发人员便无需考虑清理内存的事情了。运行时会自动知晓哪些内存不再使用了,然后释放掉它。也就是说,它自动地回收了这些垃圾。第一代的垃圾回收器是1959年Lisp引入的,这项技术迄今为止一直在不断演进。

引用计数

刚才我们用C++的共享指针所演示的想法可以应用到所有的对象上来。许多语言比如说Perl, Python以及PHP,采用的都是这种方式。这个通过一张图可以很容易说明:

什么是垃圾回收

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

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

看起来还不错对吧?没错,不过这里存在着一个重大的缺陷。很容易会出现一些孤立的环,它们中的对象都不在任何域内,但彼此却互相引用导致引用数不为0。下面便是一个例子:

什么是垃圾回收

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

有几种方法可以解决这一问题,比如说使用特殊的“弱”引用,或者使用一个特殊的算法回收循环引用。之前提到的Perl,Python以及PHP等语言,都是使用类似的方法来回收循环引用的,不过这已经超出本文讲述的范围了。我们准备详细介绍下JVM所采用的方法。

标记删除

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

  • 局部变量

  • 活动线程

  • 静态字段

  • JNI引用

  • 其它(后面将会讨论到)

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

  • 标记是指遍历所有可达对象,然后在本地内存中记录这些对象的信息

  • 删除会确保不可达对象的内存地址可以在下一次内存分配中使用。

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

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

什么是垃圾回收

缺点就是应用程序的线程需要被暂停才能完成回收,如果引用一直在变的话你是无法进行计数的。这个应用程序被暂停以便JVM可以收拾家务的情况又被称为Stop The World pause(STW)。这种暂停被触发的可能性有很多,不过垃圾回收应该是最常见的一种。


© 著作权归作者所有

共有 人打赏支持
潭州学院
粉丝 13
博文 23
码字总数 38387
作品 0
长沙
私信 提问
一张图看懂JVM之垃圾回收算法详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/t4i2b10X4c22nF6A/article/details/84143047 导读 在之前的内容中,我们通过一张图的方式(图),从总体上对J...

JAVA高级架构v
前天
0
0
JVM系列开篇:为什么要学虚拟机?

跟许多人一样,我一开始接触 Java 虚拟机只是因为面试需要用到,所以硬着头皮看看。所以很多人对于为什么要学虚拟机这个问题,他们的答案都是:因为面试。但我经过了几年的学习和实战,我发现...

陈树义
11/06
0
0
Java虚拟机必学之四大知识要点你掌握了吗?

作为一位 Java 程序员,在尽情享受 Java 虚拟机带来好处的同时,我们还应该去了解和思考“这些技术特性是如何实现的”,去了解最底层的原理。只有熟悉 JVM,你才能在遇到 OutOfMemory 等异常...

Java干货分享
10/17
0
0
My java——JVM(垃圾回收)四

续My java——JVM(内存域) 中讲述了Java在JVM中的内存使用,其实在我们出来java程序时基本上有两个地方的内存处理 一是栈、二是堆,JVM会自动回收堆中的内存,也就我们所说的垃圾回收,那J...

tngou
2013/03/20
0
0
Java面试中,遇到这类面试题最吃亏!

从你接触 Java开发到现在,你对 Java最直观的印象是什么呢?是它宣传的 “Compile once, run anywhere”,还是目前看已经有些过于形式主义的语法呢?你对于 Java平台到底了解到什么程度?请你...

Java大蜗牛
07/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

手写一个重试机制程序(使用Callable)

java.util.concurrent.Callable<V>接口可以实现多线程,同时还能实现一个简易重试机制。 查看Callable接口源码可知,它内部的call()方法带返回值,同时抛出了异常。 public interface Cal...

哥本哈根的小哥
9分钟前
0
0
能否通过反射修改被 final 修饰的成员变量?

一、背景 日常磨刀 二、阅前须知知识点: 当final修饰的成员变量在定义的时候初始化值,反射就不能动态修改它的值了。 当final修饰的成员变量在定义的时候没有初始化值,就还能通过反射来动态...

jack__0023
28分钟前
0
0
方之熙博士被任命为RISC-V基金会中国顾问委员会主席,加速RISC-V ISA在中国的应用

中国顾问委员会将就RISC-V基金会的教育和应用推广战略提供指导 今天在中国乌镇举行的世界互联网大会(World Internet Conference)上,RISC-V基金会(RISC-V Foundation)宣布,半导体行业资深人...

whoisliang
41分钟前
1
0
为了用户体验,不要做浏览器兼容

读者看到这篇文章的标题也许会感到奇怪,按照通常的经验来说,为了用户体验应该做浏览器兼容,以便让不同的浏览器用户都能有好的体验,从而增加网站的流量,但是我认为做浏览器兼容属于同样的...

Bob2100
42分钟前
1
0
分布式定时任务架构 (二) xxl-job二次开发实践

4个月前,公司有任务调度的需求,需要一周内完成,时间非常紧。 需求有三点: web界面编辑cron表达式,启动,停止任务 接入公司的rpc成本较低,公司有自研的rpc,研发人员希望共用同一套注解 ...

勇哥和你一起学技术
58分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部