说到垃圾回收,就必须得提到Lisp语言,Lisp语言是使用垃圾回收的始祖,后来的Java、Chttps://www.liuwanlin.info/superlin%e7%9a%84%e8%af%bb%e4%b9%a6%e7%ac%94%e8%ae%b0-52/、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的垃圾回收方式。