【JavaScript】数据结构与内存中的堆和栈

目录

  • 前言
  • 一 堆栈
  • 二 堆栈与内存泄漏
  • 写在最后

前言

电脑中一个很重要的部件是内存条,绝大多数时候咱们在操控一部分ram运行咱们的程序,因而就涉及到了堆栈的概念,鉴于老是记不住要查,写一篇比较简单的来记一下堆栈。浏览器

一 堆栈

堆栈是一个计算机专用术语,在数据结构里它表明着两种数据的操做方式,在内存维度里表明着两种不一样的缓存方式和分配。缓存

1.1 数据结构中的堆栈

栈(stack): 相对来讲你们比较熟悉一些,其数据的存取方式是先进后出,如同一个只有一个单元一层只有一户的筒子楼倒着看(奇怪的比喻,-_-||主要是想说明空间与门牌号关系的感受),举个例子,js中的全局下文栈在运行时是第一个进(push)栈的,在浏览器关闭时成为最后一个出(pop)栈的。其余的函数上下文也是存储在栈中,可是通常都是即进(函数建立)即出(函数执行完毕)的,bash

堆(heap): 一种通过排序的树形结构,一般用来实现优先队列,有小顶堆和大顶堆两种,能够看做一个像树同样的书架,每本书的区域存放着必定特性的数据,能够直接拿放。(没具体写过)数据结构

1.2 存储空间中的堆栈(上下文与深浅拷贝)

栈区: 闭包

前面特地用上下文的存取举了个栈结构的栗子,那么js中除了上下文引用类型,别的类型的变量都存在哪里呢?dom

首先能够肯定的是基本类型都存放在栈区,该类型的数据存在该变量门牌号(地址)的房间里(数据值)。因此当你在拷贝一个值给另外一个变量时,传递的是一个单纯的值,不会再产生任何指向运算。而当你在声明一个引用类型时,该变量所在的房间里存放的数据实际是一个地址值,该地址指向了内存中的另外一块区域——堆区。函数

堆区:性能

当引用类型被浅拷贝时,由于所分配的数据空间是同一块,位于堆中的某一个位置。因此浅拷贝的数据值被所引用的引用类型变量所共同使用,一发则同全身。优化

而被深拷贝的时候,会根据执行从新分配一块新的内存空间,两个栈上的引用类型的变量指向运算后会指向堆中不一样的地址空间。这个时候,你们各干各的,雨各自无瓜。spa

这样,在咱们想要深拷贝的场景中,咱们对引用类型拷贝时就不能使用直接赋值这种方式了,而是要从新分配一块空间给被拷贝值。

举个最简单的例子:

function deepCopy(obj) { return JSON.parse(JSON.stringify(obj)); } // 最经常使用场景使用

固然,若是遇到无函数可调用时,那么就须要手撸了,这里只提与本文最核心一行:

if (isType(parent, 'xType')) {   child = xTypeInstance}复制代码

二 堆栈与内存泄漏

2.1 内存泄漏

what

在某种场景下,对于分配的空间失去控制或者忘记释放,这些空间就属于泄漏掉的内存,在一些严重的递归或者是定时器场景中,内存泄漏会使浏览器内存占用愈来愈高,影响性能。

why

为何会产生内存泄漏,由于那部分空间不能被垃圾回收机制所回收。

在IE9之前,有两种引用类型变量的垃圾回收策略,IE对于DOM对象会进行引用计数回收,而对于JS对象进行标记清除回收。

IE9之后浏览器对引用类型变量统一使用标记清除策略。

要去优化内存的时候,不用必定要记什么dom引用js对象,js引用dom对象,或者是计时器对象未被清除,闭包产生泄漏什么的,只须要理解标记清除的原理去分析就能够了,全局变量所有被标记为window引用,局部随着所在函数上下文出栈而失去引用被即刻释放,若是局部返回一个对象使仍然访问到局部中的某些变量,则这些变量就没有失去引用,天然就会继续占据内存空间。随着一些场景中对这些返回的对象的需求结束,那么咱们就须要释放这些被绑在全局上的对象,则那些被对象所引用的变量的空间也会由于失去引用而被清除标记,随后在浏览器的gc中被回收。

How to release 

将该变量的引用赋值为null或者是将dom对象移除,在被多个对象引用时则都要处理才会释放空间。

写在最后

虽然上面列举了内存泄漏的缘由和处理方式,可是其实咱们应该注意的是去避免这些问题的出现,而有一些场景好比闭包产生的变量由于它是咱们刻意去引用的,因此并不属于垃圾,不须要被回收。人为回收前其实更要在写代码时就注意避免不规范的写法以及不一样场景变量是否属于垃圾的摇摆。

相关文章
相关标签/搜索