浅谈基本的垃圾回收方式

说到垃圾回收,就必须得提到Lisp语言,Lisp语言是使用垃圾回收的始祖,后来的Java、C#、Python、Php、Javascript等语言都借鉴了Lisp垃圾回收的思想。

12bet,总体来说垃圾回收主要有三种方式:引用计数标记清除复制。12博体育,即使是各个语言都有自己的垃圾回收方式,无非是吸收以上几种方法的特点,进行一些组合或改进来扬长避短。像Java、Javascript这些语言对垃圾回收进行了分代处理,也只是对于不同代的内存采用了不一样的垃圾回收策略,但是实质核心还是前面提到的那几种方法。

下面先说一说这三种垃圾回收方式:

引用计数

12bet,引用计数的主要思想是为内存中的每个对象保持一个计数器,如果一个对象的引用次数为0,那么这样的对象就可以作为垃圾回收了。例如:A、B都是Obj对象的引用,那么Obj的引用计数为2,12博体育,如果某函数调用返回后,A的生命周期结束,那么Obj的引用计数就为1,如果Obj的引用次数变为0,那么它就可以回收了。

12bet,这种方式的缺点就是如果两个对象互相引用,就无法回收这两个对象了,即使以后再也不会使用这两个对象,他们也会占用内存。

标记清除

12bet,标记清除的主要思想是先建立各个对象的关联,然后从根节点出发,使用广度优先搜索依次标记所有对象,那些不能被标记的对象就应该作为垃圾回收。

这种方式的主要缺点就是如果某些对象被清理后,内存是不连续的,那么就算内存占用率不高,例如只有50%,但是由于内存空隙太多,后来的大对象甚至无法存储到内存之中。

对于这种垃圾回收方式的缺点,一般的处理方式都是在垃圾回收后进行整理操作,这种方法也叫标记整理,整理的过程就是将不连续的内存向一端复制,使不连续的内存连续起来。

复制

复制的主要思想是将内存分为使用区域和备用区域,每次只将对象保存在使用区域,垃圾回收时将可用的对象复制到备用区域,然后备用区域和使用的区域的地位互换。

这种方式的缺点是显而易见的,那就是会浪费很大一部分内存,如果备用区和使用区一样大,实际浪费的内存达到了50%,而且如果内存较大,频繁的复制是相当耗时的。

复制虽然简单、方便,但是问题也很突出,针对其缺点不同的语言有不同的考虑。例如Java在新生代的垃圾回收方式就是就用了这种方法的思想,只不过Java将内存分为了2个10%的surviver区和1个80%的eden区,每次只有一个surviver区是空闲的,那么其内存的实际空闲率只有10%,对应于原始的复制方法,其实质相当于将使用区和备用区的比例设置为9:1,而不是原来的1:1,这样就大大提高了内存的使用率。之所以采用这种设计,其主要考虑就是每次存活的对象是不足10%,所以理论上从10%的备用区是完全够用的。

相信阅读本文大家对于基本的垃圾回收方式就有所了解了。下一篇文章我们将以Javascript为例,和大家探讨Javascript的垃圾回收方式。

Author image
关于 superlin
Beijing, CN 主页
The reason why a great man is great is that he resolves to be a great man.
默认颜色 边栏居左 边栏居右