JS进阶系列之内存空间
也许很多人像我一样,觉得JS有垃圾回收机制,内存就可以不管了,以至于在全局作用域下定义了很多变量,自以为JS会自动回收,直到最近,看了阮一峰老师,关于javascript内存泄漏的文章时,才发现自己写的代码,存在很严重的内存泄漏问题,再者,因为忽略对内存的学习,导致后面很多进阶概念很模糊,比如深复制与浅复制的区别,比如闭包、作用域链等等。
堆与栈
与C/C++不同,JavaScript语言没有严格意义上,区分堆与栈,所以我们可以理解为,JavaScript所有的数据都是存放在堆内存中。
不过,在某些场景下,我们仍然需要借助堆栈数据结构来处理,所以有必要理解一下这两个数据结构的区别。
栈:也叫做堆栈
栈数据结构的一个特点就是后进先出,好比羽毛球盒子,在一头放羽毛球,在另外一头取羽毛球。
堆数据结构,好比书架上的书,虽然已经按顺序放好了,但是我们只要知道书的名字,就可以对应的取下来,类似于JSON对象中的key-value。
变量对象与基本数据类型
JavaScript中的数据类型大致分为,基本数据类型与引用数据类型,上文提到,JavaScript中所有的数据都是存放在堆内存中,但是,这里提到的变量对象(在执行上下文创建阶段生成),由于它有特殊的职能,所以在理解上就把它与堆内存单独分开了,如下图所示:

一般变量对象里面存放的是基本数据类型,包括Undefined、Null、Boolean、Number、String,它们到是按值访问的。
demo01
var a = 20;
var b = a;
b = 30;
console.log(a);//20
上面这段代码指的是,在变量对象中执行数据复制的时候,其实系统会自动为新的变量分配一个新的值,所以a与b其实已经是完全独立的两个变量,只是值一样而已。

堆内存与引用数据类型
javascript中的引用数据类型是存放在堆内存中的,但是不同于变量对象,javascript是不允许直接访问堆内存中的数据,所以如果我们要访问引用数据类型的时候,采用的是按引用访问,其实就是在变量对象中存放了一个指向对象的句柄,可以理解为一个地址,要访问堆内存中的对象,就要通过这个引用句柄来访问,例如上图中的d变量,就是一个指向对象的地址。
demo02
var m = { a:10,b:20};
var n = m;
n.a = 15;
console.log(m.a);//15
上面这段代码指的是执行引用类型数据的复制时,在变量对象中会分配一个新的值,来存放新的变量,但是这两个变量的地址是一样的,相当于指向的对象是一样的,所以各自改变对象里面的属性值,会互相影响,如下图

内存泄漏
上面讲解了JavaScript中的内存空间,接下来就要讲解,我写这篇文章的初衷,就是我代码中严重的内存泄漏
内存泄漏:就是不再用到的内存,但是没有及时释放,就叫做内存泄漏
有些语言必须手动释放内存,程序员负责内存的管理,例如C语言
char *buffer;
buffer = (char*) malloc(42);
//do something with buffer
free(buffer);
这里malloc就是负责分配内存,free是负责释放内存。
那么JavaScript中的垃圾回收机制又是怎么一回事呢?
垃圾回收机制
以前我一直天真的以为,垃圾回收机制就像人工智能一样,会自动帮你识别出不用的内存,然后释放掉,然而真相只有一个
垃圾回收机制的原理就是,使用引用计数法,就是语言引擎有一张“引用表”,保存了内存里面所有的资源的引用次数,就像下面这样

但是如果一个值不再需要了,引用数却不为0,垃圾回收机制是无法释放这块内存,从而导致``内存泄漏```
例如:
const arr = [1,2,3,4,5];
console.log('hello world");
arr的引用次数为1,尽管后面不再使用arr了,但是它还会持续占用内存,所以一般要这样处理
const arr = [1,2,3,4,5];
console.log('hello world");
arr = null;
让arr的指向为空,垃圾回收机制就会默认它的引用数为0而回收掉。
避免内存泄漏
在局部作用域中,等函数执行完毕,变量就没有存在的必要了,js垃圾回收机制很快做出判断并且回收,但是对于全局变量,很难判断什么时候不用,所以,经验之谈就是,尽量少使用全局变量。
我们在使用闭包的时候,就会造成严重的内存泄漏,因为闭包的原因,局部变量会一直保存在内存中,所以在使用闭包的时候,要多加小心。
JS进阶系列之内存空间的更多相关文章
- 【 D3.js 进阶系列 】 进阶总结
进阶系列的文章从去年10月开始写的,晃眼又是4个多月了,想在年前总结一下. 首先恭祝大家新年快乐.今年是羊年吧.前段时间和朋友聊天,聊到十二生肖里为什么没猫,我张口就道:不是因为十二生肖开会的时候猫迟 ...
- 【 D3.js 进阶系列 — 4.0 】 绘制箭头
转自:http://www.ourd3js.com/wordpress/?p=660 [ D3.js 进阶系列 — 4.0 ] 绘制箭头 发表于2014/12/08 在 SVG 绘制区域中作图,在绘制 ...
- 【 D3.js 进阶系列 — 1.1 】 其它表格文件的读取
CSV 表格文件是以逗号作为单元分隔符的,其他还有以制表符 Tab 作为单元分隔符的 TSV 文件,还有人为定义的其他分隔符的表格文件.本文将说明在 D3 中怎样读取它们. 1. TSV 表格文件是什 ...
- 【 D3.js 进阶系列 — 1.2 】 读取 CSV 文件时乱码的解决方法
在 D3 中使用 d3.csv 读取 CSV 文件时,有时会出现乱码问题. 怎么解决呢? 1. 乱码问题 使用 d3.csv 读取 xxx.csv 文件时.假设 xxx.csv 文件使用的是 UTF- ...
- JS进阶系列之作用域链
在之前写的进阶系列里面,提到了执行上下文在创建阶段,要创建变量对象.确定作用域链还有确定this的指向,本次将重点讲解一下作用域链. JavaScript代码的执行过程 在讲解作用域链之前,首先了解一 ...
- 【 D3.js 进阶系列 — 6.1 】 缩放的应用(Zoom)
缩放(Zoom)是另一种重要的可视化操作,主要是使用鼠标的滚轮进行. 1. zoom 的定义 缩放是由 d3.behavior.zoom() 定义的. var zoom = d3.behavior.z ...
- 【 D3.js 进阶系列 — 2.1 】 力学图的事件 + 顶点的固定
本章讨论在力学图中经常使用到的事件( Event ),然后对[p=555">进阶 - 第 2.0 章]的人物关系图进行改进.使用户可以固定拖拽的对象. 在[入门 - 第 9.2 章]和 ...
- JS进阶系列之闭包
刚刚总结完作用域链,我觉得很有必要马上对闭包总结一下,因为,之前也写过自己对闭包的理解,那时候只知道,闭包就是可以访问别的函数变量的函数,就是在函数里面的函数就叫做闭包,可是并没有深入探究,为什么,可 ...
- 【 D3.js 进阶系列 — 1.0 】 CSV 表格文件的读取
在入门系列的教程中.我们经常使用 d3.json() 函数来读取 json 格式的文件.json 格式非常强大.但对于普通用户可能不太适合,普通用户更喜欢的是用 Microsoft Excel 或 O ...
随机推荐
- java maven项目找不到jconsole-1.8.0.jar和tools-1.8.0.jar包
今天在整合jar包时候,出现了 这是我导入的jar坐标 <dependency> <groupId>com.alibaba</groupId> <artifa ...
- 接口自动化测试框架搭建 – Java+TestNG 测试Restful service
接口自动化测试 – Java+TestNG 测试 Restful Web Service 关键词:基于Rest的Web服务,接口自动化测试,数据驱动测试,测试Restful Web Service, ...
- iOS 第三方框架-MBProgressHUD
MBProgressHUD提示框官网地址:https://github.com/jdg/MBProgressHUD 官网里已经提供了足够多的例子供我们使用,但在实现开发中,我们用到的只是其中的一小部分 ...
- BCB ERROR:[Linker Error] 'XXX.LIB' contains invalid OMF record, type 0x21 (possibly COFF)
今天C++builder 导入 gts .lib (gts.dll)库文件 编译报错: [Linker Error] 'D:\...\V4.05.007.1000-20161028\GTS.LIB' ...
- discuz $_G变量
class.core.php中 global $_G; $_G = array( 'uid' => 0, 'username' => ...
- C/S模型之TCP协议
服务端: // WSASever.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <WinSock2.h> # ...
- mybatis打印sql日志配置
<settings> <!-- 打印查询语句 --> <setting name="logImpl" value="STDOUT_LOGGI ...
- python认识快速入门(一)
接下来的一个多月开始学习python,在记录这些随笔的同时,如果你们能看到,希望能帮助到你们,如果有错误也请你们给指教! 主要记录的是对python的一个整体认识. 1.print 语句及“Hello ...
- Linux基础命令---mknod
mknod 创建块设备或者字符设备文件.此命令的适用范围:RedHat.RHEL.Ubuntu.CentOS.SUSE.openSUSE.Fedora. 1.语法 mknod [选项] ...
- python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法
python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法window安装redis,下载Redis的压缩包https://git ...