引用计数算法
2024-01-17 19:42:44引用计数算法是早先的一种垃圾回收机制算法,由于存在重大问题,目前基本上不使用了。
通过跟踪实际对象的引用次数,如果变成零引用(表示没有其他变量对其引用),那么就会进行垃圾回收,释放其内存。
计算过程
当声明一个变量,并将实际对象的引用(指针对象,指向是实际对象的开始地址)赋值给该变量的时候,那么这个实际对象的引用次数就为1。
如果实际对象的引用又被赋给另一个变量,那么引用次数+1。
如果变量的值被赋予其他的值(不是指向这个实际对象了),则引用次数-1。
当这个实际对象的引用次数变为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对象,也就避免了上面的问题。