JavaScript自动内存管理与垃圾回收策略详细分析讲解

 更新时间:2023年01月03日 09:16:25   作者:似曾不相识  
JS的垃圾回收机制是为了以防内存泄漏,内存泄漏的含义就是当已经不需要某块内存时这块内存还存在着,垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存。因为内存的大小是有限的,所以当内存不再需要的时候,我们需要对其进行释放

自动内存管理

JavaScript编程语言通过自动内存管理实现内存分配和闲置资源回收。

简单来讲就是:只要确定某个变量X不会再被使用了,就将变量X占用的内存进行释放。这种判断是周期性执行的,即:垃圾回收程序隔一定时间就会自动执行一次,以释放某些不必要的内存开支。

JavaScript垃圾回收过程中的难点在于:如何正确判定一块内存是否还有用?

垃圾回收策略

在C/C++程序中,我们记忆比较深刻的可能是它的“指针机制”,因为这些指针的存在,内存管理是靠程序员手动分配和释放的。相较JavaScript的自动内存管理方式,显得更为繁琐和复杂。

但是,如第一部分所讲,JS垃圾回收的难点在于:如何判定一块内存是否还有用?举个简单的例子,以函数call()的调用为例:

<script>
    function call(){
        const name = 'Hello';
        console.log(name);
    }
    call();
</script>

在调用函数时,会为函数体的执行开辟新的内存空间。call()函数内部定义了局部变量name,并且将其输出在控制台;输出结束,call()函数也执行结束,函数体执行过程退出;此时,不再需要call()函数的局部变量name,那么,name占用的内存就可以被释放了,空出来的内存在之后可以被程序的其它部分使用。

但是,并非所有的内存有用性判定都会如此清晰,假如:在call()函数内部形成了闭包,对变量的生存周期进行了延展处理等等,所以,垃圾回收程序必须去追踪记录变量的状态,以确定:哪个变量还会被使用?哪个变量不会再被使用?以便于内存回收。

而如何标记未使用的变量,也有不同的实现方式。在浏览器的发展史上,用到过两种如下的主要标记策略。

标记清理策略

JavaScript最常用的垃圾回收策略是“标记清理(mark-and-sweep)”。

基本思路是:当变量进入上下文,比如:函数内部声明一个变量时,这个变量就会被加载存在于上下文中的标记。而不在上下文中的变量,逻辑上讲,永远不应该释放它们的内存,因为只要上下文的代码在运行,就有可能用到这些不在上下文中的变量。此外,当变量离开上下文时,也会被加上离开上下文的标记。

在垃圾回收程序运行的时候,会使用新的标记符号标记内存中存储的所有变量。然后,将所有在上下文中的变量、以及被在上下文中的变量引用的变量上面的标记去掉,经过一轮筛选,剩下的仍然带有特殊标记的变量就是将要被删除的垃圾了。原因在于:这些带有特殊标记的变量在任何上下文中的都不会被使用到了。接着,垃圾回收程序执行一次内存清理,销毁带标记的所有值并回收它们的内存。

至2008年,IE、FireFox、Opera、Chrome和Safari都在自己的JavaScript实现中采用这种标记清理策略,只是在实现细节上有所不同。

引用计数策略

“引用计数(reference counting)”策略不太常用,其思路是:对每个值都记录它被引用的次数。例如:声明一个变量X并给X赋值为999,此时,这个值999的引用次数就为1.如果同一个值999又被赋值给另一个变量Y,那么值999的引用次数+1=2.类似的,如果保存该值999的引用变量X被其它值(如:null)给覆盖掉了,那么值999的引用次数就-1=1.

而当一个值的引用数为0时,就说明没有任何变量引用到这个值了,就可以安全地收回内存了。当垃圾回收程序下一次执行时,就可以释放引用数为0的值所在的内存空间。

但是,这种策略存在“循环引用”的问题,导致某些值的引用数永远不会变为零,也就没有机会被清理掉,引发内存泄露。

内存管理技巧

在使用垃圾回收的编程环境中,开发者通常无需关心内存管理。但是,JavaScript运行在一个内存管理和垃圾回收都十分特殊的环境中。因为操作系统可分配给承载JavaScript程序的网页程序的内存量是十分有限的,这种内存限制不仅影响变量分配,同时也影响调用栈以及能够在同一个线程中执行的语句数量。

将网页程序的内存占用量保持在一个较小的值,可以让页面的性能更优。

解除引用

优化内存占用的最佳手段就是保证在程序运行过程中只保存必要的数据,如果数据不再必要,那么就将其设置为null,从而释放其引用,这可称为“解除引用”。这个技巧最适合用于全局变量和全局对象的属性上,因为局部变量在超出最大作用域之后,就会被自动解除引用。

如下,函数createObject()执行完毕,会返回一个Object对象,同时内部的局部变量obj会自动解除与new Object()对象之间的引用关系;而在全局范围内,globalObject对象获取到了Object对象的引用;随后,当该对象不再被使用时,就应当由开发者主动解除引用。

//创建一个对象
function createObject(name){
    let obj = new Object();
    obj.name = name;
    return obj;
}
//全局变量
const globalObject = createObject("Tom");
//当该对象不再被使用时,进行解除引用
globalObject = null;

解除对一个值的引用的并不会自动导致相关的内存被回收,而是在于,解除引用可以保证相关的值不再存在于上下文环境中了,这样,垃圾回收程序下一次执行时,这个值所在的内存空间就会被回收。

const和let变量声明

ES6新增的关键字const、let,不仅有助于改善代码风格,而且同样有助于垃圾回收的过程。因为const和let都以块(而非函数)为作用域,所以相比于var,使用这两个关键字,可能会更早的让垃圾回收程序介入,尽早回收掉应该回收的内存。

到此这篇关于JavaScript自动内存管理与垃圾回收策略详细分析讲解的文章就介绍到这了,更多相关JS自动内存管理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 原生JS实现微信通讯录

    原生JS实现微信通讯录

    这篇文章主要为大家详细介绍了原生JS实现微信通讯录,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-06-06
  • 一文详解JS私有属性的6种实现方式

    一文详解JS私有属性的6种实现方式

    class是创建对象的模版,由一系列属性和方法构成,用于表示对同一概念的数据和操作。有的属性和方法是对外的,但也有的是私有的。本文梳理了六种私有属性的实现方式,需要的可以参考一下
    2022-03-03
  • JavaScript中的原型和继承详解(图文)

    JavaScript中的原型和继承详解(图文)

    到现在,我们就有讨论 JavaScript 中的原型和继承问题的基础了。它虽然并不像你在 C++、Java 或 C# 中了解的经典继承模式一样,但这种方式同样强大,并且有可能会更加灵活
    2014-07-07
  • JS获取数组最大值、最小值及长度的方法

    JS获取数组最大值、最小值及长度的方法

    这篇文章主要介绍了JS获取数组最大值、最小值及长度的方法,涉及JavaScript遍历数组及length属性的相关使用技巧,非常简洁实用,需要的朋友可以参考下
    2015-11-11
  • js为什么[]==![]是成立的吗

    js为什么[]==![]是成立的吗

    本文主要介绍了js为什么[]==![]是成立的吗,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • TypeScript mixin提升代码复用性的方法和原理

    TypeScript mixin提升代码复用性的方法和原理

    在前端开发中,我们经常需要在不同的组件或类之间共享功能代码,Mixin提供了一种非常灵活的方式,可以让我们在不破坏继承关系的前提下,将功能代码复用到多个对象中,文章通过代码示例介绍mixin提升代码复用性的方法和好处,需要的朋友可以参考下
    2023-06-06
  • 解决layui下拉框监听问题(监听不到值的变化)

    解决layui下拉框监听问题(监听不到值的变化)

    今天小编就为大家分享一篇解决layui下拉框监听问题(监听不到值的变化),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-09-09
  • 学习JS中的DOM节点以及操作

    学习JS中的DOM节点以及操作

    本篇文章给大家整理了关于JS中DOM节点的相关知识点以及代码实例,有兴趣的朋友可以跟着学习下。
    2018-04-04
  • javascript 模拟点击广告

    javascript 模拟点击广告

    我们不管js或iframe怎么调用的,模拟点击就意味着打开广告链接,广告商就以为用户点击了他的广告,所以我们只要保证点击了一个链接但没有跳出页面的结果就行了,是吗?
    2010-01-01
  • js为鼠标添加右击事件防止默认的右击菜单弹出

    js为鼠标添加右击事件防止默认的右击菜单弹出

    本文为大家介绍下如何为使用js为鼠标添加右击事件防止默认的右击菜单弹出,感兴趣的朋友可以参考下,希望对大家有所帮助
    2013-07-07

最新评论