js内存空间的那点事
由于js具有自动垃圾回收机制,导致接触js后一直没去关注js的内存分配及变量回收等原理,只是懵懂的了解用变量标记法(null)可以手动的去清除或是回收;是时候弥补这个大坑了...
垃圾回收两种方法 一种是 标记清除法另外一种是计数清除法,下面都会提到;
先来回顾/了解下垃圾回收实现算法----Mark-and-sweep, 此算法实现步骤:
垃圾回收器创建了一个“roots”列表。Roots 通常是代码中全局变量的引用。JavaScript 中,“window” 对象是一个全局变量,被当作 root 。window 对象总是存在,因此垃圾回收器可以检查它和它的所有子对象是否存在(即不是垃圾);
所有的 roots 被检查和标记为激活(即不是垃圾)。所有的子对象也被递归地检查。从 root 开始的所有对象如果是可达的,它就不被当作垃圾。
所有未被标记的内存会被当做垃圾,收集器现在可以释放内存,归还给操作系统了。
可以简单的理解为 垃圾回收器会从window开始递归的标记window下所有子对象,在能访问到的子对象上边做个标记 告诉收集器这个对象/属性我罩着 你不能动.而那些没被标记的就视为"垃圾", 收集器会将它们释放掉, window只是roots之一 对于其他的对象来讲也是一样的 ;
JS变量类型分为两种即 原始类型(Number, String, Boolean, null, undefined)与引用类型(Object, Function, Array);
栈: 遵循着后进先出,先进后出的原则, 属于一级缓存, 地位相当于cpu的寄存器, 由编译器自动分配释放, 读写快, 存储的都是固定值(也就是原始类型);
堆: 属于二级缓存,由我们分配释放, 要是没有手动的释放,在调用结束后可能由GC回收,其生命周期由虚拟机的垃圾回收算法来决定。存储的是引用类型;
在Js中 是不许直接操作堆的, 所以栈与堆的区分不是那么严谨, 只要用到了堆, 必然也用到了栈;上一段代码帮助理解:
var a = 1, b = {m:20};
看起来像这样:
可以清晰的看到在栈内存中变量b 存的是一个地址(引用地址,这个地址存放的就是{m: 20}), 由此我们可以看到js是不能直接操作堆的,操作的是这个引用地址; 而这个地址存放于栈中, 这就好理解为什么js栈与堆区分的不是那么严谨了.如果我们改变b的值,那会发生些什么,好,把b 改成b = [1, 2, 3]:
{m: 20}成了孤儿了.没人罩着他了,所以os会处理掉. 这里就是os的另一种回收条件了--计数清除.将一个引用类型的值赋值给一个变量,那么这个引用类型的值的引用次数就加1,相反,如果这个变量被赋值了其他值,这个引用类型的值的引用次数就减1,当引用次数为0时,就说明没有办法再访问这个引用类型的值了,那么她所占的内存空间会被垃圾回收器给回收;
接下来深浅复制就好理解了. 浅复制复制的引用地址, b复制了a的引用地址 他俩只要有一个对地址内容进行改变别人都会收到. 就像是你吧自家钥匙给了一朋友,他买了一个新电脑进来, 当你回家你也会发现这个电脑;深复制呢,没错你给你朋友的不在是一把钥匙而是一个房子, 这样他在那房子干点什么你完全不知道也不受影响.下面在看看执行环境与栈之间的关系,看一段代码:
var a = 1; function fn(){ var b = 2; function fn1(){ console.log(b); } fn1(); } fn();
运行后大致如下:
先进后出,所以会先进入fn1的执行环境..当fn1执行完在进入fn..一直到全局的执行环境,全局执行上下文永远处于栈底.截止到这类似下面这些题一看就会了..
var a = 1, b = a; a = 2; //b?
没错 b还是1; 因为1是number 位于栈内存, b=a 的时候会深复制过来;
var a = {n: 1}, b = a; a.n = 2; //b.n?
对于这种一年级的问题我们先放一放, 考虑这段代码会引发什么问题(不用考虑兼容性):
var obj = document.getElementById("button");// 假设可以获取到这个id为 button的Dom元素; obj.addEventListener("click",function(){ obj.style.background = "#f00"; },false);
确实会引发内存泄漏的情况, 原因就是回调里边使用obj 保留了对外部obj的引用,导致不能被回收.;
类似这样的:
var num= 12;
setInterval(function() {
var obj = document.getElementById('button');
if(obj) {
obj.innerHTML = num;
}
}, 1000);
内存泄漏不是想避免就能避免的, 写代码有意识的防范固然很重要,也要学会使用调试工具进行探查.
对还有一点:
解除引用并不代表收回该值所占的内存,解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其收回;好吧. 对于js内存空间也就这点事了..
js内存空间的那点事的更多相关文章
- JS内存空间详细图解
JS内存空间详细图解 变量对象与堆内存 var a = 20; var b = 'abc'; var c = true; var d = { m: 20 } 因为JavaScript具有自动垃圾回收机 ...
- js内存空间详细图解-笔记
原文参考http://mp.weixin.qq.com/s/NGqdjhoU3MR9LD0yH6tKIw 栈-先进后出堆-类比成书于书架(形象),只要知道Key就可以找到value 基础数据类型(Un ...
- 前端高质量知识(一)-JS内存空间详细图解
变量对象与堆内存 var a = 20; var b = 'abc'; var c = true; var d = { m: 20 } 因为JavaScript具有自动垃圾回收机制,所 ...
- js内存空间
堆数据结构 堆数据结构是一种树状结构.它的存取数据的方式与书架和书非常相似.我们只需要知道书的名字就可以直接取出书了,并不需要把上面的书取出来.JSON格式的数据中,我们存储的key-value可以是 ...
- js内存空间及this关键词详解
http://mp.weixin.qq.com/s/FYFepXmkzzDYNLKhpovYFA
- js基础梳理-内存空间
我估计有很多像我这样非计算机专业的人进入到前端之后,总是在写业务代码,思考什么什么效果如何实现,导致很多基础概念型的东西都理解得并不太清楚.经常一碰到群里讨论的些笔试题什么的,总觉得自己像是一个假前端 ...
- js内存深入学习(一)
一. 内存空间储存 某些情况下,调用堆栈中函数调用的数量超出了调用堆栈的实际大小,浏览器会抛出一个错误终止运行.这个就涉及到内存问题了. 1. 数据结构类型 栈: 后进先出(LIFO)的数据结构 堆 ...
- 【进阶1-3期】JavaScript深入之内存空间详细图解(转)
这是我在公众号(高级前端进阶)看到的文章,现在做笔记 https://mp.weixin.qq.com/s/x4ZOYysb9XdT1grJbBMVkg 今天介绍的是JS内存空间,了解内存空间中的堆和 ...
- 由js深拷贝引起的对内存空间的一些思考
数据类型 js常用数据类型分为基本类型和引用类型 基本类型:null.undefined.数值型.字符串型.布尔型 引用类型:数组.对象 内存空间 var a = [1, 2, 3]; var b = ...
随机推荐
- Mac 笔记本 开发日记
1.录屏,截图 Mac 自带录屏功能 command +control +o 2.复制当前应用,在启一个当前app窗口 command+n 3.快速回到桌面 command +f3 4.选中文件,复制 ...
- 详解网络传输中的三张表,MAC地址表、ARP缓存表以及路由表
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://dengqi.blog.51cto.com/5685776/1223132 一:M ...
- Redis核心原理
Redis系统介绍: Redis的基础介绍与安装使用步骤:https://www.jianshu.com/p/2a23257af57b Redis的基础数据结构与使用:https://www.jian ...
- DB2(Procedure)存储过程遍历循环!
有时候一些复杂的业务逻辑将要通过存储过程的循环语句进行处理;以下列出2种DB2存储过程的循环语句,方便以后的查看并使用! 推荐第一种方式的使用,最大的优点就是比较直观;在需要操作很多字段的情况下,不需 ...
- OpenJudge NOI 4976 硬币
http://noi.openjudge.cn/ch0207/4976/ 描述 宇航员Bob有一天来到火星上,他有收集硬币的习惯.于是他将火星上所有面值的硬币都收集起来了,一共有n种,每种只有一个:面 ...
- lambda正则化参数的大小影响
当lambda的值很小时,其惩罚项值不大,还是会出现过拟合现象,当时lambda的值逐渐调大的时候,过拟合现象的程度越来越低,但是当labmda的值超过一个阈值时,就会出现欠拟合现象,因为其惩罚项太大 ...
- Dubbo helloword
首先,开始编写服务提供者的api接口, SampleService 接口 package bhz.dubbo.sample.provider; import java.util.List; publ ...
- FortiGate 5.2/5.4 SSLVPN建立
1.定义源IP池 即用户通过sslvpn拨号成功后获取到的IP地址. 2.定义路由地址 即用户通过sslvpn拨号成功后允许获取到的路由表. 3.建立sslvpn portal 4.定义用户和用户组 ...
- MySQL往表里插入千条数据 存储过程
工作中遇到的问题,先记录一下,方便以后查看 存在两张表,user表和friend表 user表部分字段,如上图 friend表部分字段,如上图 往friend表插入千条数据,friend表中的user ...
- Annotation 标注
1.画出基本图 当图线中某些特殊地方需要标注时,我们可以使用 annotation. matplotlib 中的 annotation 有两种方法, 一种是用 plt 里面的 annotate,一种是 ...