纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

JS内存空间 详解JS内存空间

lsgxeva   2021-06-09 我要评论
想了解详解JS内存空间的相关内容吗lsgxeva在本文为您仔细讲解JS内存空间的相关知识和一些Code实例欢迎阅读和指正我们先划重点:JS,内存空间下面大家一起来学习吧

概述

变量对象与堆内存

var a = 20;
var b = 'abc';
var c = true;
var d = { m: 20 }

在很长一段时间里认为内存空间的概念在JS的学习中并不是那么重要可是后我当我回过头来重新整理JS基础时发现由于对它们的模糊认知导致了很多东西我都理解得并不明白比如最基本的引用数据类型和引用传递到底是怎么回事儿?比如浅复制与深复制有什么不同?还有闭包原型等等

因此后来我才渐渐明白想要对JS的理解更加深刻就必须对内存空间有一个清晰的认知

一、栈与堆

注:栈也可以叫堆栈

与C/C++不同JavaScript中并没有严格意义上区分栈内存与堆内存因此我们可以粗浅的理解为JavaScript的所有数据都保存在堆内存中但是在某些场景我们仍然需要基于堆栈数据结构的思路进行处理比如JavaScript的执行上下文(关于执行上下文我会在下一篇文章中总结)执行上下文在逻辑上实现了堆栈因此理解堆栈数据结构的原理与特点任然十分重要

要简单理解栈的存取方式我们可以通过类比乒乓球盒子来分析如下图左侧

乒乓球盒子与栈类比

这种乒乓球的存放方式与栈中存取数据的方式如出一辙处于盒子中最顶层的乒乓球5它一定是最后被放进去但可以最先被使用而我们想要使用底层的乒乓球1就必须将上面的4个乒乓球取出来让乒乓球1处于盒子顶层这就是栈空间先进后出后进先出的特点图中已经详细的表明了栈空间的存储原理

堆存取数据的方式则与书架与书非常相似

书虽然也整齐的存放在书架上但是我们只要知道书的名字我们就可以很方便的取出我们想要的书而不用像从乒乓球盒子里取乒乓一样非得将上面的所有乒乓球拿出来才能取到中间的某一个乒乓球好比在JSON格式的数据中我们存储的key-value是可以无序的因为顺序的不同并不影响我们的使用我们只需要关心书的名字

二、变量对象与基础数据类型

JavaScript的执行上下文生成之后会创建一个叫做变量对象的特殊对象(具体会在下一篇文章与执行上下文一起总结)JavaScript的基础数据类型往往都会保存在变量对象中

严格意义上来说变量对象也是存放于堆内存中但是由于变量对象的特殊职能我们在理解时仍然需要将其于堆内存区分开来

基础数据类型都是一些简单的数据段JavaScript中有5中基础数据类型分别是Undefined、Null、Boolean、Number、String基础数据类型都是按值访问因为我们可以直接操作保存在变量中的实际的值

三、引用数据类型与堆内存

与其他语言不通JS的引用数据类型比如数组Array它们值的大小是不固定的引用数据类型的值是保存在堆内存中的对象JavaScript不允许直接访问堆内存中的位置因此我们不能直接操作对象的堆内存空间在操作对象时实际上是在操作对象的引用而不是实际的对象因此引用类型的值都是按引用访问的这里的引用我们可以粗浅地理解为保存在变量对象中的一个地址该地址与堆内存的实际值相关联

为了更好的搞懂变量对象与堆内存我们可以结合以下例子与图解进行理解

var a1 = 0;   // 变量对象
var a2 = 'this is string'; // 变量对象
var a3 = null; // 变量对象

var b = { m: 20 }; // 变量b存在于变量对象中{m: 20} 作为对象存在于堆内存中
var c = [1, 2, 3]; // 变量c存在于变量对象中[1, 2, 3] 作为对象存在于堆内存中

上例图解

因此当我们要访问堆内存中的引用数据类型时实际上我们首先是从变量对象中获取了该对象的地址引用(或者地址指针)然后再从堆内存中取得我们需要的数据

理解了JS的内存空间我们就可以借助内存空间的特性来验证一下引用类型的一些特点了

在前端面试中我们常常会遇到这样一个类似的题目

// demo01.js
var a = 20;
var b = a;
b = 30;

// 这时a的值是多少?
// demo02.js
var m = { a: 10, b: 20 }
var n = m;
n.a = 15;

// 这时m.a的值是多少

在变量对象中的数据发生复制行为时系统会自动为新的变量分配一个新值var b = a执行之后a与b虽然值都等于20但是他们其实已经是相互独立互不影响的值了具体如图所以我们修改了b的值以后a的值并不会发生变化

demo01图解

在demo02中我们通过var n = m执行一次复制引用类型的操作引用类型的复制同样也会为新的变量自动分配一个新的值保存在变量对象中但不同的是这个新的值仅仅只是引用类型的一个地址指针当地址指针相同时尽管他们相互独立但是在变量对象中访问到的具体对象实际上是同一个如图所示

因此当我改变n时m也发生了变化这就是引用类型的特性

demo02图解

通过内存的角度来理解是不是感觉要轻松很多除此之外我们还可以以此为基础一步一步的理解JavaScript的执行上下文作用域链闭包原型链等重要概念其他的我会在以后的文章慢慢总结敬请期待

内存空间管理

因为JavaScript具有自动垃圾收集机制所以我们在开发时好像不用关心内存的使用问题内存的分配与回收都完全实现了自动管理但是根据我自己的开发经验了解内存机制有助于自己清晰的认识到自己写的代码在执行过程中发生过什么从而写出性能更加优秀的代码因此关心内存是一件非常重要的事情

JavaScript的内存生命周期

1. 分配你所需要的内存

2. 使用分配到的内存(读、写)

3. 不需要时将其释放、归还

为了便于理解我们使用一个简单的例子来解释这个周期

var a = 20;  // 在内存中给数值变量分配空间
alert(a + 100);  // 使用内存
var a = null; // 使用完毕之后释放内存空间

第一步和第二步我们都很好理解JavaScript在定义变量时就完成了内存分配第三步释放内存空间则是我们需要重点理解的一个点

JavaScript有自动垃圾收集机制那么这个自动垃圾收集机制的原理是什么呢?其实很简单就是找出那些不再继续使用的值然后释放其占用的内存垃圾收集器会每隔固定的时间段就执行一次释放操作

在JavaScript中最常用的是通过标记清除的算法来找到哪些对象是不再继续使用的因此a = null其实仅仅只是做了一个释放引用的操作让 a 原本对应的值失去引用脱离执行环境这个值会在下一次垃圾收集器执行操作时被找到并释放而在适当的时候解除引用是为页面获得更好性能的一个重要方式

在局部作用域中当函数执行完毕局部变量也就没有存在的必要了因此垃圾收集器很容易做出判断并回收但是全局变量什么时候需要自动释放内存空间则很难判断因此在我们的开发中需要尽量避免使用全局变量以确保性能问题要详细了解垃圾收集机制建议阅读《JavaScript高级编程》中的4.3节


相关文章

猜您喜欢

  • Java访问修饰符 深度理解Java访问修饰符

    想了解深度理解Java访问修饰符的相关内容吗dz小伟在本文为您仔细讲解Java访问修饰符的相关知识和一些Code实例欢迎阅读和指正我们先划重点:Java四种访问修饰符,Java访问修饰符下面大家一起来学习吧..
  • App保活技术实现 详解App保活技术实现

    想了解详解App保活技术实现的相关内容吗lsgxeva在本文为您仔细讲解App保活技术实现的相关知识和一些Code实例欢迎阅读和指正我们先划重点:App,保活下面大家一起来学习吧..

网友评论

Copyright 2020 www.fresh-weather.com 【世纪下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式