内存专题

最后更新于:2022-04-01 04:52:16

## 内存专题 > * `JAVASCRIPT`的内存回收机制 > * 以Google的`V8`引擎为例,在`V8`引擎中所有的`JAVASCRIPT`对象都是通过`堆`来进行内存分配的。当我们在代码中`声明变量`并`赋值`时,`V8`引擎就会在`堆内存`中分配一部分给这个`变量`。如果已申请的`内存`不足以存储这个`变量`时,`V8`引擎就会继续申请`内存`,直到`堆`的大小达到了`V8`引擎的内存上限为止(默认情况下,`V8`引擎的`堆内存`的大小上限在`64位系统`中为`1464MB`,在`32位系统`中则为`732MB`)。 > * 另外,`V8`引擎对`堆内存`中的`JAVASCRIPT`对象进行`分代管理`。 > * 新生代。 > * 新生代即存活周期较短的`JAVASCRIPT`对象,如临时变量、字符串等 > * 老生代。 > * 老生代则为经过多次垃圾回收仍然存活,存活周期较长的对象,如主控制器、服务器对象等。 > * 垃圾回收算法。 > * 垃圾回收算法一直是编程语言的研发中是否重要的​​一环,而`V8`引擎所使用的垃圾回收算法主要有以下几种。 > * `Scavange`算法:通过复制的方式进行内存空间管理,主要用于新生代的内存空间; > * `Mark-Sweep`算法和`Mark-Compact`算法:通过标记来对堆内存进行整理和回收,主要用于老生代对象的检查和回收。 > * 对象进行回收。 > > > * `引用`。 > > > * 当函数执行完毕时,在函数内部所声明的对象`不一定`就会被销毁。 > * 引用(`Reference`)是`JAVASCRIPT`编程中十分重要的一个机制。 > > > * 是指`代码对对象的访问`这一抽象关系,它与`C/C++`的指针有点相似,但并非同物。引用同时也是`JAVASCRIPT`引擎在进行`垃圾回收`中最关键的一个机制。 > > > > ~~~ > var val = 'hello world'; > function foo() { > return function() { > return val; > }; > } > global.bar = foo(); > ~~~ > > > * 当代码执行完毕时,对象`val`和`bar()`并没有被回收释放,`JAVASCRIPT`代码中,每个`变量`作为单独一行而不做任何操作,`JAVASCRIPT`引擎都会认为这是对`对象`的访问行为,存在了对`对象的引用`。为了保证`垃圾回收`的行为不影响程序逻辑的运行,`JAVASCRIPT`引擎不会把正在使用的`对象`进行回收。所以判断`对象`是否正在使用中的标准,就是是否仍然存在对该`对象`的`引用`。 > > > * `JAVASCRIPT`的`引用`是可以进行`转移`的,那么就有可能出现某些引用被带到了全局作用域,但事实上在业务逻辑里已经不需要对其进行访问了,这个时候就应该被回收,但是`JAVASCRIPT`引擎仍会认为程序仍然需要它。 > * `IE`下闭包引起跨页面内存泄露。 > * `JAVASCRIPT`的内存泄露处理 > > > * 给`DOM`对象添加的属性是一个对象的引用。 > > > > ~~~ > var MyObject = {}; > document.getElementByIdx_x('myDiv').myProp = MyObject; > ~~~ > > > > 解决方法:在window.onunload事件中写上: > > > > ~~~ > document.getElementByIdx_x('myDiv').myProp = null; > ~~~ > > > * DOM对象与JS对象相互引用。 > > > > ~~~ > function Encapsulator(element) { > this.elementReference = element; > element.myProp = this; > } > new Encapsulator(document.getElementByIdx_x('myDiv')); > ~~~ > > > > 解决方法:在onunload事件中写上: > > > > ~~~ > document.getElementByIdx_x('myDiv').myProp = null; > ~~~ > > > * 给DOM对象用attachEvent绑定事件。 > > > > ~~~ > function doClick() {} > element.attachEvent("onclick", doClick); > ~~~ > > > > 解决方法:在onunload事件中写上: > > > > ~~~ > element.detachEvent('onclick', doClick); > ~~~ > > > * 从外到内执行appendChild。这时即使调用removeChild也无法释放。 > > > > ~~~ > var parentDiv = document.createElement_x("div"); > var childDiv = document.createElement_x("div"); > document.body.appendChild(parentDiv); > parentDiv.appendChild(childDiv); > ~~~ > > > > 解决方法:从内到外执行appendChild: > > > > ~~~ > var parentDiv = document.createElement_x("div"); > var childDiv = document.createElement_x("div"); > parentDiv.appendChild(childDiv); > document.body.appendChild(parentDiv); > ~~~ > > > * 反复重写同一个属性会造成内存大量占用(但关闭IE后内存会被释放)。 > > > > ~~~ > for(i = 0; i < 5000; i++) { > hostElement.text = "asdfasdfasdf"; > } > ~~~ > > > > 这种方式相当于定义了5000个属性,解决方法:无。 > > > * `内存`不是`缓存`。 > * 不要轻易将`内存`当作`缓存`使用。 > * 如果是很重要的资源,请不要直接放在`内存`中,或者制定`过期机制`,自动销毁`过期缓存`。 > * `CollectGarbage`。 > * `CollectGarbage`是`IE`的一个特有属性,用于释放内存的使用方法,将该变量或引用对象设置为`null`或`delete`然后在进行释放动作,在做`CollectGarbage`前,要必需清楚的两个必备条件:(引用)。 > * 一个对象在其生存的上下文环境之外,即会失效。 > * 一个全局的对象在没有被执用(引用)的情况下,即会失效
';