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

正文
  如果真的想学好一门语言,那么一定要了解它内存模型,本篇文章就带你走进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. Patterns-Proxy

    http://blog.csdn.net/jianghuxiaoxiami/article/details/3403924 1.代理模式 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问 ...

  2. 【BIRT】报表显示不全

    使用BIRT开发了一张报表,预期效果如下 但是开发完成后预览效果如下: 最后的合计竟然没有了,那么怎么处理呢 鼠标点击Layout窗口空白部分,找到布局,切换为自动布局,如下图所示:

  3. 用oracle建表,必须注意Oracle 关键字(保留字)

    Oracle 关键字(保留字) 大全   转 其实这个东西可以在oracle 上输入一个sql语句就可以得到: select * from v$reserved_words order by keyw ...

  4. [hdu 4959]Poor Akagi 数论(卢卡斯数,二次域运算,等比数列求和)

    Poor Akagi Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tot ...

  5. android下载

    1. 源码下载链接: http://source.android.com/source/downloading.html 参考链接: Android源码下载方法详解 2. SDK下载 http://d ...

  6. Javascript遍历页面控件

    function validate(){ //var Elements = document.all;  var Elements = document.getElementsByTagName(&q ...

  7. C#指南,重温基础,展望远方!(8)C#数组

    数组是一种数据结构,其中包含许多通过计算索引访问的变量. 数组中的变量(亦称为数组的元素)均为同一种类型,我们将这种类型称为数组的元素类型. 数组类型是引用类型,声明数组变量只是为引用数组实例预留空间 ...

  8. T-sql for xml path使用(转)

    参考: http://www.cnblogs.com/langhua/p/4193161.html //用法: FOR XML PATH 方法是用于将查询结果集以XML形式展示 sql: p.Cont ...

  9. SQL面试题与附解收集(一)

    数据库三范式是什么? 答: 1NF:字段不可分; 2NF:有主键,非主键字段依赖主键; 3NF:非主键字段不能相互依赖; 解释: 1NF:原子性 字段不可再分,否则就不是关系数据库; 2NF:唯一性 ...

  10. 数据库入门级面试题(带答案) 数据库简单面试题(带答案) MySQL面试题带答案

    数据库入门[mysql]   1.假设要按照分页(每页显示10条)的形式获取test表中的数据,在MySql数据库中,以下哪条语句是取第2页中的数据?(单选)   (难度A) A.select * f ...