在JavaScript中,最独特的一个特色就是拥有自动的垃圾回收机制(周期性执行),这也就意味者,前端开发人员可以专一于业余,从而减小在内存的管理,提升开发的效率。javascript
用户自定义的对象、函数,但这些都是咱们肉眼不可见的,而是依靠在外部的媒介“内存条”中,自动垃圾回收的本质也就是找出已再也不使用的变量、函数,释放其占用的内存空间前端
当再也不须要某样东西时会发生什么? JavaScript 引擎是如何发现并清理它?java
JavaScript 中内存管理的主要概念是可达性。api
简单地说,“可达性” 值就是那些以某种方式可访问或可用的值,它们被保证存储在内存中。数据结构
本地函数的局部变量和参数dom
当前嵌套执行上下文其余函数的变量和函数函数
全局变量学习
若是引用或者引用链能够经过根访问到任何其余值,则认为该值是可访问的3d
实际上网页的元素就是由一个个对象构建成了一个dom树(特殊的图结构)(树结构是单向,图结构是双向的,)指针
经过JavaScipt提供的api咱们能够找到页面上指定元素的对象,并对其进行操做
每个DOM元素对象均可以看做是一个根,咱们能够还能够访问自身元素的亲戚
父元素
兄弟元素
祖先元素
后代元素
var user = { name : 'EYS', }
这里的箭头表示一个对象引用,全局变量 "user" 引用对象{name : 'EYS'} user对象中的name属性存储了一个基本类型的数据
但若是user的值被覆盖,则引用丢失
user = null;
如今user变成不可达的状态,没有办法访问以前的值,他们之间没有联系,就被JavaScript引擎发现他了!!!而后就把他丢到小黑屋去了,自动释放了它所占用的内存空间
// user具备对象的引用 var user = { name: "John" }; var admin = user; //引用传递
该对象仍然能够经过 admin 全局变量访问,因此它在内存中。若是咱们也覆盖admin,那么它能够被释放。
function marry (man, woman) { woman.husban = man; man.wife = woman; return { father: man, mother: woman } } let family = marry({ name: "John" }, { name: "Ann" })
产生的内存结构:
内存中的图片变成:
如今让咱们删除两个引用:
delete family.father; delete family.mother.husband;
仅仅删除这两个引用中的一个是不够的,由于全部对象仍然是可访问的。
输出引用可有可无。只有传入的对象才能使对象可访问,所以,John 如今是不可访问的,并将从内存中删除全部不可访问的数据。
垃圾回收以后:
family = null;
可是若是咱们把这两个都删除,那么咱们能够看到 John 再也不有传入的引用:
“family”对象已经从根上断开了连接,再也不有对它的引用,所以下面的整个块变得不可到达,并将被删除。
分为『进入环境』和『离开环境』
进入环境 : 指变量进入的执行环境
离开环境 : 指变量完成任务,离开了执行的环境
垃圾收集器会在脚本运行的时候给存储在内存中的全部变量都加上标记
它会去掉环境中的变量以及被环境中的变量引用的变量的标记
而在此以后再被加上标记的变量将被视为准备删除的变量,缘由是环境中的变量已经没法访问到这些变量了
最后,垃圾收集器完成内存清除工做,销毁那些带标记的值并回收它们所占用的内存空间
含义 : 跟踪记录每一个值被引用的次数
当用户声明了一个变量并将一个引用类型值赋给该变量时,则这个值的应用次数就为1 【声明变量并赋值】
若是同一个值又被赋给另外一个变量,则该值的引用次数加 1 【变量的值传递】
若是包含这个值引用的变量被覆盖了,则以前的值的应用次数减1 【覆盖变量以前的值】
当这个值的引用次数变成 0 时,则说明没有办法再访问这 个值了,于是就能够将其占用的内存空间回收回来。 【变量回收】
这种机制其实在js中并不经常使用,由于这种机制会产生循环引用的问题,『循环引用』指的是对象 A 中包含一个指向对象 B 的指针,而对象 B 中也包含一个指向对象 A 的引用。对于像js类的自动回收机制的语言来讲,须要额外手动的去释放内存,其实并不友好。
在学习内存空间以前,咱们须要对三种数据结构有一个清晰的理解。他们分别是堆(heap),栈(stack)与队列(queue)。
JavaScript中并无严格意义上区分栈内存与堆内存
如JavaScript的执行上下文(关于执行上下文我会在下一篇文章中总结)。执行上下文的执行顺序借用了栈数据结构的存取方式(也就是后面咱们会常常提到的函数调用栈)。所以理解栈数据结构的原理与特色十分重要。
JavaScript的数据类型分为两种 : 基本类型,引用类型
咱们能够简单粗暴的理解 基本类型数据是存储在栈,引用类型的数据是存储在堆中,等待变量创建引用关系
要简单理解栈的存取方式,咱们能够经过类比乒乓球盒子来分析。以下图左侧。
基本特征为 : 先进后出,后进先出
堆数据结构是一种树状结构。它的存取数据的方式,则与书架与书很是类似。
书虽然也整齐的存放在书架上,可是咱们只要知道书的名字,就能够很方便的取出咱们想要的书,而不用像从乒乓球盒子里取乒乓同样,非得将上面的全部乒乓球拿出来才能取到中间的某一个乒乓球。比如在JSON格式的数据中,咱们存储的key-value是能够无序的,由于顺序的不一样并不影响咱们的使用,咱们只须要关心书的名字。
队列是一种先进先出(FIFO)的数据结构。正如排队过安检同样,排在队伍前面的人必定是最早过检的人。用如下的图示能够清楚的理解队列的原理。