<!--
浏览器垃圾回收制:
1----引用计数算法:
2----标记清除算法:
将不再使用的对象 ---- 定义为无法到达的对象!!!
即从根部(在JS中就是全局对象)出发定时扫描内存中的对象,凡是能从根部到达的对象,保留。那些从根部出发无法触及到的对象被标记为不再使用,稍后进行回收。
无法触及的对象包含了没有引用的对象这个概念,但反之未必成立。
所以上面的例子就可以正确被垃圾回收处理了。
所以现在对于主流浏览器来说,只需要切断需要回收的对象与根部的联系。最常见的内存泄露一般都与DOM元素绑定有关:
a = null 其实仅仅只是做了一个释放引用的操作,让 a 原本对应的值失去引用,脱离执行环境,这个值会在下一次垃圾收集器执行操作时被找到并释放。
而在适当的时候解除引用,是为页面获得更好性能的一个重要方式。
实际上是将变量脱离执行环境,断开引用的一种操作!!!
首先JavaScript在被浏览器执行的时候,会分为三个阶段:
1、定义阶段,在内存当中定义一个,执行环境栈(Global main),将window对象(全局执行上下文 或者 全局作用域)放入执行栈当中。
2、生成活动对象AO(active Object)scope执行栈,函数执行的时候,会将函数执行上下文(局部作用域)push到活动对象当中,活动对象遵循先进后出的原则,
当函数执行完成以后会进行出栈操作(失去引用关系,会被下次垃圾回收机制回收。),每次执行函数的时候创建的函数执行上下文都是最新的!!!
Javascript被浏览器执行为什么是单线程?
JavaScript 是浏览器脚本语言,它可以操纵 DOM ,可以渲染动画,可以与用户进行互动,
如果是多线程,执行顺序无法预知,操作以哪个线程很难预知。
单线程是JavaScript脚本语言的核心特征。
补充:
在 HTML5 时代,浏览器为了充分发挥 CPU 性能优势,允许 JavaScript 创建多个线程,
但是即使能额外创建线程,这些子线程仍然是受到主线程控制,而且不得操作 DOM,------类似于开辟一个线程来运算复杂性任务,
运算好了通知主线程运算完毕,结果给你(主线程),这类似于异步的处理方式,所以本质上并没有改变 JavaScript 单线程的本质。
函数调用栈 --------------------------------------------- 任务队列
JavaScript 只有一个主线程和一个调用栈(call stack)。 所有任务可以分成两种,一种是 同步任务(synchronous),
代码执行,进栈,执行完毕,出栈。 另一种是 异步任务(asynchronous) 。
----------------------------------------------------
什么是同步任务和异步任务?
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。
异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有 "任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
所以,当在执行过程中遇到一些类似于 setTimeout 等异步操作的时候,会交给浏览器的其他模块进行处理,
当到达 setTimeout 指定的延时执行的时间之后,回调函数会放入到任务队列之中。
当然,一般不同的异步任务的回调函数会放入不同的任务队列之中。等到调用栈中所有任务执行完毕之后,接着去执行任务队列之中的回调函数。
什么是事件循环?:
调用栈顺序调用任务----------------------(往调用栈里面push任务,顺序执行同步任务)
当调用栈发现异步任务时,将异步任务交给其他模块处理,自己继续进行下面的调用
异步执行完毕,异步模块将任务推入任务队列,并通知调用栈
调用栈在执行完当前任务后,将执行任务队列里的任务
调用栈执行完任务队列里的任务之后,继续执行其他任务
-----------------这一整个流程就叫做 事件循环(Event Loop)。
价值非常高解释调用栈---任务队列
for (var i = 0; i < 10; i++) {
setTimeout(() => {
console.log(i)
}, 1000)
}
console.log(i)
复制代码解析:
首先由于 var 的变量提升,i 在全局作用域都有效
再次,代码遇到 setTimeout 之后,将该函数交给其他模块处理,自己继续执行 console.log(i) ,由于变量提升,i 已经循环10次,此时 i 的值为 10 ,即,输出 10
之后,异步模块处理好函数之后,将回调推入任务队列,并通知调用栈
1秒之后,调用栈顺序执行回调函数,由于此时 i 已经变成 10 ,即输出10次 10
-----------------------------------------------------
引发问题:
全局作用域不是包含局部作用域吗?
不矛盾。
什么叫内存泄漏?:
(对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。)
对于不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)
总结:
总之,变量之间的引用关系,变量是否存在于执行环境中是重点!!!(闭包原理亦如此!!!)
eg:
var div = document.createElement("div");
div.onclick = function() {
console.log("click");
};
注释:
变量div有事件处理函数的引用,同时事件处理函数也有div的引用!(div变量可在函数内被访问)。-----(细细的品)
-----IE采用的是引用计数算法,因此这里存在内存泄漏。
-->