JS数据类型转换与内存模型

JS数据类型转换与内存模型

  • JS数据类型转换
  • 拓展知识:内存与外存
  • 基础数据类型,对象,栈内存与堆内存
  • 一道经典(SB)面试题的内存分析
  • 垃圾回收与内存泄漏
  • 深拷贝与浅拷贝的概念

JS数据类型转换

一张图表示,简单明了~

拓展:内存与外存

内存

内存分为RAM和ROM。RAM是随机存取存储器,用户可读可写,计算机断电后,存储在RAM的信息将被删除。RAM具体分为SRAM(Static RAM)和DRAM(Dynamic RAM)。我们 现在所说的内存一般指的都是DRAM,SRAM速度更快,但是容量相对于其他类型内存而言也会小一些,并且价格也较为昂贵。一般SRAM作为CPU和DRAM之间的缓存(cache)。ROM是只读存储器,ROM的内容是制造商写进去的,用户只能读,但不能写。ROM在切断电源后,数据也不会丢失。计算机会给当前执行的程序动态地分配内存空间,例如用户打开浏览器打开诸多网页,计算机会给浏览器分配内存,浏览器会给每一个页面分配内存,会给页面的HTML,CSS,JS分配内存。

外存

因为内存中的数据在断电之后会消失,所以为了数据的保存,就需要使用其他类型的存储器。这类存储器一般是磁盘,固态硬盘(ssd)等,也就是所谓的外存。

基础数据类型,对象,栈内存与堆内存

JS中的基础数据类型往往都保存在栈内存中,因为这些值都有固定的大小。
例如:var a = 1; 内存分配图大概是这个样子的:


JS中复杂数据类型即对象,例如数组,函数,由于它们的值大小非固定,所以它们的值实际上保存在堆内存当中。而栈内存中保存的是指向实际对象值的引用,这个引用我们可以理解为一个地址。也就是说,在我们操作对象时,实际上操作的是指向这个对象的引用,而并非是实际的对象。
例如: var a = {'key':'value'}; 内存分配图大概是这个样子的:


一道经典(SB)面试题的内存分析

var a = {n:1};
var b = a;
a.x = a = {n:2};
=============================
问:
console.log(a.x)= ?
console.log(b.x) =?
复制代码

这道题涉及到了连续赋值的情况,在程序运行之后,先确定好了a.x 和 a的引用,然后再从右往左开始赋值 。本题的内存分析如下:

var a = {n:1};
var b = a;
复制代码

代码执行到这里时,内存图模型如下:


在执行代码 a.x = a = {n:2};时,JS首先会确定a在stack中的“地址”也就是指向对象的引用。

a.x = a = {n:2};
// 本例中a在stack中的地址为addr=31,在确定好这个信息后,代码会从右至左开始执行。
复制代码

首先是a = {n:2}


然后执行 a.x = a,在内存模型中,此时左边的a在stack中对应的地址为addr31,而右边的a在stack中的地址已经变为了addr33。所以这个操作相当于在addr31所指向的对象中添加x属性,x的属性值为addr33指向的对象。


所以结果如下:

垃圾回收与内存泄漏

参考内容:JavaScript内存管理一文。

JS内存的声明周期
  1. 内存分配:在声明变量,对象时,系统会对内存进行自动分配
  2. 内存使用:在读写内存时,也就是我们在使用声明的变量,对象时,称为内存使用过程
  3. 内存回收:当一些数据被浏览器视作“垃圾”时,浏览器内部的GC回收机制会回收不再使用的内存。
垃圾回收算法
引用计数算法

引用计数算法定义“垃圾”的标准很简单,就是看一个对象是否有指向它的引用,如果没有就回收。但是引用计数算法却存在着许多问题,试想如果在堆内存中,有对象相互引用,即便是它们不再使用,但是GC不会进行回收,最后就会导致内存泄漏的问题,而IE6就是使用引用计数算法来进行垃圾回收的。
如代码:

function c() {
    var o1 = {};
    var o2 = {};
    o1.a = o2;
    o2.a = o1; 
    
    return "IE6'Bug"
}

c();
复制代码

按理来讲方法在调用之后,对象o1,o2可以进行回收了,但是在堆内存中两者互相引用,是根据引用计数算法的定义,在堆内存的这两个对象还存在着引用的关系,所以这部分内存不会被回收,接下来就有可能带来内存泄漏的问题。什么是内存泄漏呢?内存泄漏(Memory Leak) 是指在程序中动态被分配的堆内存中,由于某种原因,导致程序未被释放或者说无法释放而造成了系统内存的浪费,进而导致程序运行速度减慢,甚至是系统崩溃。

标记清除算法

标记清除算法是现代浏览器主要使用,并在此之上加以改进并应用的算法,标记清除算法定义“垃圾”为从栈内存开始“无法达到”的对象。对于IE6出现的Bug,即便是堆内存中两个对象互相引用的情况,标记清除算法也可以进行回收。

深拷贝与浅拷贝的概念

如:

var a = 1;
var b = a;
复制代码

这个过程就是深拷贝,对于基本类型来说,赋值的过程就是深拷贝。当我们尝试去改变b的值时,变量a的值不会发生变化,换句话说,一个变不会影响另一个这就是深拷贝。浅拷贝则恰恰相反,对于复杂类型而言:

var a = {name:'a'};
var b = a;
复制代码

a和b指向同一个对象,当改变a.name或b.name时,另外的引用指向的对象(其实就是自己)会发生改变,所以我们可以这么理解:一个变会影响另一个变这就是深拷贝。对于复杂类型来说,也可以通过代码实现深拷贝,后续再见~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值