一个热爱技术的菜鸟...用点滴的积累铸就明日的达人

正文
  如果真的想学好一门语言,那么一定要了解它内存模型,本篇文章就带你走进JavaScript的内存模型,由于本人才疏学浅,若有什么表述有误的地方,欢迎各位看官能够指点一二,在此不胜感激...
  在阅读这边文章之前,默认您已经掌握了JavaScript的基本概念、栈堆等基本数据结构以及计算机基本理论基础,如有了解欠缺,请移步相关博客后再阅读本文。
一、基本的数据类型的内存结构
  首先粗略的介绍一下JavaScript中五种基本的数据类型Undefined、Null、Boolean、Number、String;其中对于Undefined与Null的区别,网上有很多大牛都有介绍,在此本文暂不涉及,如有疑虑之处,请移步相关博客。或许有看官会问为什么在介绍JavaScript内存模型之前要先介绍JavaScript的基本数据类型的内存结构呢?这是因为JavaScript内存模型与基本数据类型的内存结构的关系就好比数学与实数的关系,基本数据类型的内存结构是整个JavaScript内存模型的基础。那么接下来就让我以最简短的方式来阐述一下基本数据类型的内存结构吧~
  基本数据类型的内存结构:在JavaScript中基本的数据类型都是以值的形式保存在内存中的。举个例子:

var inta = 10;
var strb = 'Hello';

  那么在执行完这段JavaScript代码之后,内存中会有两个区域分别表示为inta,strb;其中表示inta区域的值为‘10’,表示strb区域的值为‘Hello’,也即表示inta与strb的内存区域保存的均为实际的真值;

二、引用数据类型的内存结构

  在JavaScript中除了基本数据类型,那就剩下引用数据类型了,所以在介绍玩基本数据类型内存结构之后,就很有必要再介绍一下引用数据类型内存结构。引用数据类型的真实对象是保存在堆内存中的,而JavaScript与Java相似,均不可以直接访问堆内存,所以都是使用“引用”这个东西来访问处于堆中的对象,引用与对象的关系可以描述成遥控器与电视机之间的关系,我们可以持有遥控器来操控电视机。所谓的引用其实就是一块内存的地址,即在表示引用的区域上保存的是内存中对象的内存地址值,如图所示:

  其中假设对象处于内存中一个位置叫做0x23215的区域,那么椭圆的区域表示这个对象的引用,椭圆区域中存的就是0x23125这个值,在实际的操作中执行环境会通过引用中存的0x23125,去找到内存中的这个对象。

三、内存模型

  在JavaScript执行时期,可以将内存从逻辑上划分为两部分:栈与堆。其中栈是在JavaScript执行时,用于储存执行上下文(后续文章会介绍)的,而堆是存储对象的区域。在执行上下文生成之后,会创建一个变量对象(后续文章会介绍),变量对象是一个特殊的对象,它也会存储在堆。基本数据类型往往都会直接保存在变量对象中,而引用数据类型实际上是在变量对象中保存一个引用指向对象的地址(也即引用本身)。

  学习完JavaScript中的内存模型之后,请各位看官看看下面这段代码,并且猜猜它的输出结果,以验证上述知识的理解程度:

var inta = 10;
var stra = 'Hello'; var obja = {a: 10, b: 'Hello'}; var intb = inta;
var strb = stra;
var objb = obja; intb = 20;
strb = 'World';
objb.a = 20;
objb.b = 'World'; console.log(inta, intb);
console.log(stra, strb);
console.log(obja, objb);

  运行结果:

10 20
Hello World
{ a: 20, b: 'World' } { a: 20, b: 'World' }

  这其中会涉及到对象的赋值问题,在对基本数据类型赋值的时候,都是将原值赋值到新的对象上,所以改变新的对象的值,并不会影响到原值(因为它们本质上保存的是两个值);而对引用数据类型赋值则是将引用所指向对象的地址赋值给另一个引用,而在后续操作中,如果通过新的引用去改变对象中内部的值的话,还是会影响原来的引用所指向的对象(因为它们本质上保存的是同一个对象)

四、内存回收机制

  JavaScript具有自动的垃圾回收机制,也即执行环境会负责代码的执行过程中使用的内存,它会定期(周期性)找出哪些不再使用的对象,然后释放其内存。目前JavaScript最常用的垃圾回收算法为标记清除算法,垃圾回收机制会通过标记的算法来决定哪些对象是不需要再次使用的,然后再进行清除,也即清理哪些被定义为垃圾的JavaScript对象。

  上述所述的不再使用的变量也就是生命周期结束的变量,当然只可能是局部变量。全局变量的生命周期直到浏览器卸载页面才会结束,所以声明一个全局变量的时候,我们一定要慎重的考虑,在使用完这个变量的对象之后,我们是否还在需要这个对象,如果不需要的话,我们应该手动的将这个变量置为空,这样在下一次垃圾回收的时候,就能去释放这个变量上一次指向的对象(请注意变量与对象的区别)。

  下面请各位看官see一下以下的代码,来分析一下垃圾回收。

function fun1() {
var obj = {name: 'csa', age: 24};
} function fun2() {
var obj = {name: 'coder', age: 2}
return obj;
} var f1 = fun1();
var f2 = fun2();

  在上述代码中,当执行var f1 = fun1();的时候,执行环境会创建一个{name:'csa', age:24}这个对象,当执行var f2 = fun2();的时候,执行环境会创建一个{name:'coder', age=2}这个对象,然后在下一次垃圾回收来临的时候,会释放{name:'csa', age:24}这个对象的内存,但并不会释放{name:'coder', age:2}这个对象的内存。这就是因为在fun2()函数中将{name:'coder, age:2'}这个对象返回,并且将其引用赋值给了f2变量,又由于f2这个对象属于全局变量,所以在页面没有卸载的情况下,f2所指向的对象{name:'coder', age:2}是不会被回收的。

  由于JavaScript语言的特殊性(闭包...),导致如何判断一个对象是否会被回收的问题上变的异常艰难,这不仅需要我们有很强的基本功,还需要在以后的项目中积累经验。最后顺便说一句,即使随着硬件的更新换代以及垃圾回收机制的改进,我们也不应该忽视垃圾回收的基本理论,因为这是提高代码性能的关键一步,只有这样我们才能写出那些堪称艺术品的代码...

JavaScript学习系列之内存模型篇的更多相关文章

  1. JVM学习笔记——内存模型篇

    JVM学习笔记--内存模型篇 在本系列内容中我们会对JVM做一个系统的学习,本片将会介绍JVM的内存模型部分 我们会分为以下几部分进行介绍: 内存模型 乐观锁与悲观锁 synchronized优化 内 ...

  2. JavaScript学习系列5 ---ES6中的var, let 和const

    我们都知道JavaScript中的var,在本系列的 JavaScript学习系列2一JavaScript中的变量作用域 中,我们详细阐述了var声明的变量的作用域 文章中提到,JavaScript中 ...

  3. JavaScript学习系列之执行上下文与变量对象篇

    一个热爱技术的菜鸟...用点滴的积累铸就明日的达人 正文 在上一篇文章中讲解了JavaScript内存模型,其中有提到执行上下文与变量对象的概念.对于JavaScript开发者来说,理解执行上下文与变 ...

  4. 【JVM】JVM系列之内存模型(六)

    一.前言 经过前面的学习,我们终于进入了虚拟机最后一部分的学习,内存模型.理解内存模型对我们理解虚拟机.正确使用多线程编程提供很大帮助.下面开始正式学习. 二.Java并发基础 在并发编程中存在两个关 ...

  5. JVM学习总结一——内存模型

    JVM是java知识体系的基石之一,任何一个java程序的运行,都要借助于他.或许对于我这种初级程序员而言,工作中很少有必要刻意去关注JVM,然而如果能对这块知识有所了解,就能够更清晰的明白程序的运行 ...

  6. 浅谈JavaScript原型图与内存模型

    js原型详解 1.内存模型: 1.原型是js中非常特殊一个对象,当一个函数(Person)创建之后,会随之就产生一个原型对象 2. 当通过这个函数的构造函数创建了一个具体的对象(p1)之后,在这个具体 ...

  7. JVM学习记录-Java内存模型(二)

    对于volatile型变量的特殊规则 关键字volatile可以说是Java虚拟机提供的最轻量级的同步机制. 在处理多线程数据竞争问题时,不仅仅是可以使用synchronized关键字来实现,使用vo ...

  8. JVM学习记录-Java内存模型(一)

    前言 Java虚拟机规范中定义了一种Java的内存模型,即Java Memoory Model(简称JMM),用来实现让Java程序在各个平台下都能达到一致的内存访问效果.JVM是整个虚拟机,JMM模 ...

  9. JVM系列.JVM内存模型

    <Java虚拟机规范>将虚拟机的内存分为以下几个区域: 堆区:堆区是JVM中最大的一块内存区域,按照垃圾分代收集的角度划分,又可以分成年轻代和老年代,而年轻代内存又被分成三部分,Eden空 ...

随机推荐

  1. Oracle学习(五):多表查询

    1.知识点:能够对比以下的录屏进行阅读 SQL> --等值连接 SQL> --查询员工信息: 员工号 姓名 月薪 部门名称 SQL> select empno,ename,sal,d ...

  2. Linux的内存映像导出接口—kcore

    发表于 2012-4-10 15:00   /proc/kcore文件提供了整个机器的内存映像,和vmcore不同的是,它提供了一个运行时的内存映像,为此和vmcore一样,内核提供了一个类似的但是稍 ...

  3. Django的CBV与FBV

    FBV FBV(function base views) 就是在视图里使用函数处理请求. 在之前django的学习中,我们一直使用的是这种方式,所以不再赘述. CBV CBV(class base v ...

  4. Mysql导入大SQL文件数据问题

    如果sql文件过大,会出现mysql out of memory  (Needed XXX bytes) ,或者 "MySQL server has gone away"问题; 另 ...

  5. JavaScript编码转换之gb2312转unicode -- &#X形式

    http://www.cnblogs.com/meil/archive/2007/01/31/635936.html JavaScript编码转换之gb2312转unicode     1. < ...

  6. phpstorm设置断点调试

    环境是:wamp PHP Version: 5.5.12 网上的教程很多,我自己按照教程操作,实现了断点调试,下面是我设置断点调试的步骤 1.修改配置文件php.ini,按下面修改(位置在最后) ; ...

  7. 架构(三层架构)、框架(MVC)、设计模式三者异同点

    前言: 本博客主要针对架构.框架和设计模式三者的区别.还有三层和MVC的区别进行讨论.对于这三者一点都不了解的.请点在维基和百度百科上补补课.这里就不发链接了 软件架构(software archit ...

  8. cocos2dx 关于lua 绑定的环境配置官方文档翻译与 将自己定义c++方法绑定到lua的的方法

    网上有好多写如何讲自己定义的方法绑定到lua的文章,当中都仅仅对环境配置做了简单的介绍,看到有的帖子写在绑定中遇到了各种各样的error.大部分是因为环境配置不对导致的,下面是官方的文档有标准的说明, ...

  9. CentOS 6.4 yum安装chrome

    CentOS 6.4安装chrome浏览器 vim /etc/yum.repos.d/CentOS-Base.repo 根据你的系统增加一个节点 32-bit [google] name=Google ...

  10. JavaScript 中 this 的用法

    在 JavaScript 中,this 是动态绑定,或称为运行期绑定的.一般而言,在Javascript中,this 指向函数执行时的当前对象. 由于其运行期绑定的特性,JavaScript 中的 t ...