垃圾回收器如何工作?

已经开学一周了,自己的状态还可以,但是3月份让我感觉更加的紧张,因为面临着春招,但是对于这次春招,表示没有什么把握了,准备努力去备战秋招

最近在看Thinking in java,当看到java垃圾回收器的工作原理的时候,把我看懵逼了,看了3-4遍,才勉强可以看懂

正文

我们知道在java中,创建对象存储在堆中,但是当出现这些对象未曾被使用的时候,这些对象将会被垃圾回收器回收掉

在java虚拟机中,堆的实现更像是一个传送带,每次分配一个新的对象的时候,传送带将往前移动一个格子,这意味着对象在存储空间的分配速度非常快。java的堆指针只是简单的移动到未分配的区域,其效率比的上
C++在堆栈上分配空间的效率。

java的对象分配并不是完全像传送带那样,否则就会导致频繁的内存页面调度,因为显得需要拥有比实际需要更多的内存,最终当创建足够多的对象之后,内存资源将被耗尽,这个原因是在于垃圾回收器的介入

在说java虚拟机是如何进行垃圾回收的时候先了解下其他系统的垃圾回收原理:

其他系统的垃圾回收原理

记数技术

count

如上图所示,在堆中有ABCDEF对象,每个对象都有一个计数器,当有引用连至对象的时候计数器加1,当离开作用域或者对象被置为null的时候,则计数器减1,虽然管理开销不大,但是存在于整个生命周期。垃圾回收器会对列表进行遍历,当发现计数器为0的时候,则对象被释放,这种技术有缺陷,如果对象之间存在循环应用的话,就会出现对象应该被回收,但是计数器不为0的情况,对垃圾回收器而言,定位这种所需要的工作量非常大,但是很少虚拟机使用这种技术

追溯活对象的方式

这种技术更像是数据结构中的网状结构,通过不断寻找使用的对象,也就是活的对象来进行垃圾回收的处理,具体:对于任何活的对象,一定能最终追溯到其存活在堆栈或者静态存储区之中的引用,这种引用穿过数个对象层次。对于发现的每个引用必须追溯到它的所引用的对象,然后是此对象包含的引用,如此的循环,直到根源于堆栈和静态存储区的应用而形成的网络全部被访问为止,这就解决了交互自引用的对象组的问题。

java虚拟机的垃圾回收

java虚拟机采用的是一种自适应的垃圾回收技术。
在java虚拟机中垃圾回收技术中有一种做法叫做,叫做停止-复制原理

停止-复制

scopy

这个地方首先需要检索所有的对象的引用,以及包含引用的对象,和上述的追溯活对象的方式差不多,然后检索完成后,将程序停止(它不属于后台回收模式),然后将活的对象复制到新的堆中,然后在之前的堆剩下的就是未曾使用的对象,这样垃圾回收就可以把这些垃圾给回收啦,对于这种所谓也成复制式回收器而言,效率就降低了,首先你必须有两个堆,然后的把这两个堆来回折腾,从而维护比实际要多一倍的时间;某些java虚拟机对此问题的处理方式是,按需从对中分配几块较大的内存,复制动作发生在这些大块内存之间

来回的复制,对于内存来说比较浪费时间和空间,为了避免这种情况,一些虚拟机会进行检查,要上没有新的垃圾产生,就会转变为另一种工作模式

标记-清扫(自适应)

所依据的思路是从堆栈和静态存储区域出发,遍历所有的引用,进而找出所有的对象,由于在这次中垃圾会比较的少,所有说在遍历的时候都会被打上一个标记,这个标记过程不会回收任何对象,只有当所有的标记完成后,才会发生清理,在清理的过程中,没有被标记的对象将会被释放,不会发生任何复制动作,所以剩下的空间是不连续的,垃圾回收器要上希望得到连续空间的话就需要重新整理下剩下的对象,

鉴于上述两种方式,就可以显得java虚拟机的垃圾回收会比较的智能,自适应,当垃圾少的话转为标记-清扫,垃圾多的话就会启用停止-复制,你可以给它一个啰嗦的称呼:自使用,分代的,停止-复制,标记-清扫式垃圾回收器


最近访客