一、JS的内存空间
JS的内存空间分为栈、堆和池。
栈中存放的一般是简单的数据,便于提升查找的效率。
而由于大部分对象这样的复杂值,它们的大小会改变,因此会存储在堆中,否则会降低变量的查询效率,此时栈中存放的是指向对象的地址。
池一般存储常量值,也会放在栈中。
JS中的基础数据类型都会放在栈中。
二、JS的垃圾回收
1、初始算法:引用计数
给对象加上一个引用计数器,如果存在其他对象对它的引用,则计数器不为0。反之,当计数器为0时,则下次垃圾回收时会将该对象看作可回收的对象。
缺点:无法解决循环引用的问题。
function cycle() {
var o1 = {};
var o2 = {};
o1.a = o2;
o2.a = o1;
return "Cycle reference!"
}
cycle();
优点:速度快
2、使用根对象I(比如window)遍历的方式确定引用关系,进行垃圾回收
以根对象作为一条可达链的根节点,根据引用关系往下遍历。
比如右边的三个对象,虽然存在互相引用的关系,但是并没有与根节点相连
谷歌浏览器中的标记--清除算法及标记-复制、标记-整理算法
在谷歌浏览器中,JS的堆同样会被V8引擎分为新生代和老年代,在新生代中采用标记-复制算法,老年代中采用标记-清除、标记-整理算法。
对下一次回收中可以进行回收的对象进行标记,在垃圾回收时清空这部分内存。
这里引用我的一篇博客来说明这些的概念。
https://blog.csdn.net/qq_43710345/article/details/105486320
然而IE低版本依然采用引用计数的方式,并且IE-8中的DOM对象也是,IE-9才换成了现在的算法。因此在对象不使用以后,为了适应这部分浏览器,应该结束对象的引用关系(特别是比较大的对象,因为浏览器的内存有限)。
DOM对象的循环引用
function f(){
var element = document.getElementById('some_element');
var myObject = new Object();
myObject.element = element;
element.someObject = myObject;
}
f()
var obj = {name: 'an object', age: 1000};
...
使用过程
...
obj=null;
垃圾回收时是按照临界值来划分的,在IE7中,如果垃圾收集例程回收的内存分配量低于15%,则变量、字面量和数组元素的临界值就会加倍。如果例程回收了85%的内存分配量,则将各种临界值重置回默认值。这样,极大地提升了IE在运行包含大量javascript的页面时的性能。
除了自动垃圾回收,我们也可以进行手动的垃圾回收,比如,在IE中可以调用window.CollectGarbage()方法来进行,但是不建议这么做。
三、内存管理中的问题
内存泄漏(没有及时释放内存)
原因:
1、缓存:缓存有助于数据的快捷复用,然而缓存无法回收,如果突破上限则有可能导致内存泄漏
2、全局变量定义的不规范,比如下面的代码,可能只是想定义局部变量,但是没有使用var/let等来定义。
function foo(arg) {
bar = "this is a hidden global variable";
}
内存溢出(空间不够用)