引用计数算法

2024-01-17 19:42:44

引用计数算法是早先的一种垃圾回收机制算法,由于存在重大问题,目前基本上不使用了。

通过跟踪实际对象的引用次数,如果变成零引用(表示没有其他变量对其引用),那么就会进行垃圾回收,释放其内存。

计算过程

  1. 当声明一个变量,并将实际对象的引用(指针对象,指向是实际对象的开始地址)赋值给该变量的时候,那么这个实际对象的引用次数就为1。

  2. 如果实际对象的引用又被赋给另一个变量,那么引用次数+1。

  3. 如果变量的值被赋予其他的值(不是指向这个实际对象了),则引用次数-1。

  4. 当这个实际对象的引用次数变为0的时候,就会进行垃圾回收,释放其内存。

举例:

let a = {}; 	// {} 被a引用,其引用次数1
let b = a; 		// {} 引用计数是 2(a, b引用)
a = null;  		// {} 引用计数为 1(b引用)
b = null;	 	// {} 引用计数为 0(无引用),下一轮垃圾回收时,将会被回收,释放其占用内存

严重问题——循环引用

什么是循环引用呢?即对象A有一个指针指向对象B,而对象B也引用了对象A。

function abc() {
    let A = {};
    let B = {};
    A.b = B;
    B.a = A;
}

上面实例中,实际对象A和实际对象B的引用计数都是2,当变量A和变量B都赋值为null后,实际对象的的引用计数为1,除非我们每次不能忘记讲A.b和B.a赋值为null,这种肯定不可能的,会有遗忘,那么如果多次执行,将会有大量的内存不被释放。

IE8及之前版本使用问题

在IE8以及更早版本的IE中,BOM和DOM对象并非是原生JavaScript对象,它是由C++实现的 组件对象模型对象(COM,Component Object Model),而COM对象使用引用计数算法来实现垃圾回收,所以即使浏览器使用的是标记清除算法,只要涉及到COM对象的循环引用,就还是无法被回收掉,就比如两个互相引用的DOM对象等等,而想要解决循环引用,需要将引用地址置为null 来切断变量与之前引用值的关系,如下:

function abc() {
    let ele = document.getElementById("root");
    let obj = {};
    // 造成循环引用
    obj.ele = ele;
    ele.obj = obj;
    // 切断引用关系
    obj.ele = null;
    ele.obj = null;
    ele = null;
    obj = null;
}

不过在IE9及以后的BOM与DOM对象都改成了JavaScript对象,也就避免了上面的问题。

目录

相关推荐
display为inline-block的元素中间有间隙的原因和解决办法面试题:new关键字做了什么面试题:this指向深入理解JS预解析(变量提升和函数提升)闭包