JavaScript数据类型和内存(内存泄漏、内存垃圾回收)

变量和内存管理

为了合理的管理内存,操作系统一般会把内存划分区域来使用,如代码区、数据区等。被编译成机器的码的程序在执行时会被复制到内存的代码区,程序中的变量和常量会被存放到数据区中。数据区,一般又分成:堆区、栈区、全局区……。各大语言的编译器的内存模型一般会有一定的差别,不过基本都有堆和栈之分。

对于JavaScript来说,为了更好的理解,也需要去讨论讨论堆和栈。

栈区一般由系统自动分配存储空间,用来存放局部变量、函数形参等一些固定大小的数据,保存在栈区的数据我们一般可以直接操作。因此,JavaScript的基础数据类型:Number String null undefined Boolean,都是存放在栈区的,是按值访问的。

在程序执行过程中申请的内存空间属于堆区,一般存放一些较大且大小不固定的数据,堆区的数据一般不能直接被访问。堆区空间一般需要程序员手动释放,若程序员不释放,程序结束时可能由系统回收 。因此,JavaScript的复杂数据类型(ObjectArrayFunction等)一般放到堆区。由于堆区的数据不能直接访问,变量的值一般存放的并不是这些数据本身,而是该数据在内存中的地址,因此这些复杂的数据类型,也被成为引用数据类型。我们访问一个堆区中的数据步骤一般是这样的:首先从栈中获取了该数据的地址引用,然后再从堆内存中取得我们需要的数据。

在这里插入图片描述

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

变量的复制

基础数据类型的变量复制
var a = 20;
// 对于存在栈区的变量,a赋值给b变量,其实是将a变量的值复制一份存到内存中,然后将b变量指向新复制的数据
// 因此a与b其实已经是完全独立的两个变量,只是值一样而已。
var b = a;
console.log(a, b);
b = 30;
console.log(a, b);

在这里插入图片描述

复杂数据类型的变量复制

JavaScript是不允许直接访问堆内存中的数据,所以如果我们要访问复杂数据类型的时候,采用的是按引用访问,其实就是在变量对象中存放了一个指向对象的句柄,可以理解为一个地址,要访问堆内存中的对象,就要通过这个引用句柄来访问。

var m = { a: 10, b: 20 };
// 复杂数据类型的赋值,其实是将变量m中存的值(堆中的地址),复制一份出来放到内存中,然后将n指向新复制的值
// 因此,其实m和n最终指向的还是同一个堆中的同一个对象
var n = m;
console.log(m, n);
n.a = 15;
console.log(m, n);

在这里插入图片描述

内存泄漏

内存泄露可以定义为:应用程序或者变量不再需要占用内存的时候,由于某些原因,该内存并没有被回收,我们就称之为内存泄漏。

内存垃圾回收

垃圾:不再需要的变量或引用即为垃圾

JavaScript垃圾回收机制常用方法:引用计数标记清除,同时垃圾收集器是周期性运行的。

引用计数

JavaScript中,引用一般是针对复杂数据类型来说的。语言引擎有一张“引用表”,保存了内存里面所有的资源的引用次数,当引用次数为0的时候,垃圾回收机制会自动的回收其内存。但是有时候我们会遇到一个值不再需要了,引用数却不为0,这种垃圾回收机制是无法释放这块内存,这就会导致内存泄漏,比如循环引用的时候。

// 单引用
var a = {name: 'ss'};
// 抹去了a对 {name: 'ss'}的引用
// {name: 'ss'} 的被引用次数就变成0了,所以它就成垃圾了
a = null;

在这里插入图片描述

// 循环引用
var a = {name: '666'};
var b = {name: '777'};
a.brother = b;
b.brother = a;
// 即使a和b分别对对象的引用断掉,其实那两个对象引用次数依然不为0
// 但实际上我们已经不需要这两个对象了
a = null;
b = null;

在这里插入图片描述

通过上面的循环引用问题,我们会看到,使用引用计数法进行垃圾回收不是很保险,可能会出现很严重的内存泄漏问题。因此,这种垃圾回收机制用的较少,已经很少有浏览器使用这种处理方式了。

标记清除

这是JavaScript中最常用的垃圾回收方式。从全局作用域开始,一层一层往下标记,当变量进入执行环境时,就标记这个变量为“进入环境”。当变量离开环境时,则将其标记为“离开环境”。所有标记为“进入环境”的变量不被清除,标记为“离开环境”的变量会被清除。

使用这种方式,我们可以看到,对于全局变量来说,只要程序还在执行,那么就不会被删除,因此我们应该尽量少用全局变量,如果使用完以后,可以手动的将其值改为null或者使用delete删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值