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

目录
  • 自动内存管理
  • 垃圾回收策略
  • 标记清理策略
  • 引用计数策略
  • 内存管理技巧
  • 解除引用
  • const和let变量声明

自动内存管理

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自动内存管理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • JavaScript的垃圾回收机制与内存管理

    如果我们想要优化性能,首先我们必须得了解JavaScript中的垃圾回收机制,这样可以将很多没有被使用到的变量从内存中清除掉,腾出更多的内存空间,给别的变量分配内存空间. JavaScript中的垃圾回收机制 引言 本篇文章将讲解一下javascript的垃圾回收机制.同时,我们必须先具备作用域链的概念,不懂的小伙伴可以先花5分钟观看一下这篇文章,简单了解一下作用域链的知识--从零开始讲解JavaScript中作用域链的概念及用途 正文 一.垃圾回收机制 在JavaScript中,具有自动垃圾回

  • 跟我学习javascript的垃圾回收机制与内存管理

    一.垃圾回收机制-GC Javascript具有自动垃圾回收机制(GC:Garbage Collecation),也就是说,执行环境会负责管理代码执行过程中使用的内存. 原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存. JavaScript垃圾回收的机制很简单:找出不再使用的变量,然后释放掉其占用的内存,但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行. 不再使用的变量也就是生命周期结束的变量,当然只可能是局部变量,全局变量的生

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

    目录 自动内存管理 垃圾回收策略 标记清理策略 引用计数策略 内存管理技巧 解除引用 const和let变量声明 自动内存管理 JavaScript编程语言通过自动内存管理实现内存分配和闲置资源回收. 简单来讲就是:只要确定某个变量X不会再被使用了,就将变量X占用的内存进行释放.这种判断是周期性执行的,即:垃圾回收程序隔一定时间就会自动执行一次,以释放某些不必要的内存开支. JavaScript垃圾回收过程中的难点在于:如何正确判定一块内存是否还有用? 垃圾回收策略 在C/C++程序中,我们记忆

  • python的内存管理和垃圾回收机制详解

    简单来说python的内存管理机制有三种 1)引用计数 2)垃圾回收 3)内存池 接下来我们来详细讲解这三种管理机制 1,引用计数: 引用计数是一种非常高效的内存管理手段,当一个pyhton对象被引用时其引用计数增加1,当其不再被引用时引用计数减1,当引用计数等于0的时候,对象就被删除了. 2,垃圾回收(这是一个很重要知识点): ①  引用计数 引用计数也是一种垃圾回收机制,而且是一种最直观,最简单的垃圾回收技术. 在Python中每一个对象的核心就是一个结构体PyObject,它的内部有一个引

  • JVM教程之内存管理和垃圾回收(三)

    JVM内存组成结构 JVM栈由堆.栈.本地方法栈.方法区等部分组成,结构图如下所示: 1)堆 所有通过new创建的对象的内存都在堆中分配,其大小可以通过-Xmx和-Xms来控制.堆被划分为新生代和旧生代,新生代又被进一步划分为Eden和Survivor区,最后Survivor由From Space和To Space组成,结构图如下所示: 新生代.新建的对象都是用新生代分配内存,Eden空间不足的时候,会把存活的对象转移到Survivor中,新生代大小可以由-Xmn来控制,也可以用-XX:Surv

  • 浅谈jvm中的垃圾回收策略

    java和C#中的内存的分配和释放都是由虚拟机自动管理的,此前我已经介绍了CLR中GC的对象回收方式,是基于代的内存回收策略,其实在java中,JVM的对象回收策略也是基于分代的思想.这样做的目的就是为了提高垃圾 回收的性能,避免对堆中的所有对象进行检查时所带来的程序的响应的延迟,因为jvm执行GC时,会stop the word,即终止其它线程的运行,等回收完毕,才恢复其它线程的操作.基于分代的思想是:jvm在每一次执行垃圾收集器时,只是对一小部分内存 对象引用进行检查,这一小部分对象的生命周

  • 深入理解JVM自动内存管理

    目录 一.前言 1.1 计算机==>操作系统==>JVM 1.1.1 虚拟与实体(对上图的结构层次分析) 1.1.2 Java程序执行(对上图的箭头流程分析) 二.JVM内存空间与参数设置 2.1 运行时数据区 2.2 关于StackOverflowError和OutOfMemoryError 2.2.1 StackOverflowError 2.2.2 OutOfMemoryError 2.3 JVM堆内存和非堆内存 2.3.1 堆内存和非堆内存 2.3.2 JVM堆内部构型(新生代和老年代

  • 浅析Java内存模型与垃圾回收

    1.Java内存模型 Java虚拟机在执行程序时把它管理的内存分为若干数据区域,这些数据区域分布情况如下图所示: 程序计数器:一块较小内存区域,指向当前所执行的字节码.如果线程正在执行一个Java方法,这个计数器记录正在执行的虚拟机字节码指令的地址,如果执行的是Native方法,这个计算器值为空. Java虚拟机栈:线程私有的,其生命周期和线程一致,每个方法执行时都会创建一个栈帧用于存储局部变量表.操作数栈.动态链接.方法出口等信息. 本地方法栈:与虚拟机栈功能类似,只不过虚拟机栈为虚拟机执行J

  • Java分代垃圾回收策略原理详解

    一.为什么要分代 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的.因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率. 在Java程序运行的过程中,会产生大量的对象,其中有些对象是与业务信息相关,比如Http请求中的Session对象.线程.Socket连接,这类对象跟业务直接挂钩,因此生命周期比较长.但是还有一些对象,主要是程序运行过程中生成的临时变量,这些对象生命周期会比较短,比如:String对象,由于其不变类的特性,系统会产生大量的这些对象,有些对象

  • 设置oralce自动内存管理执行步骤

    设置oralce自动内存管理 启用oracle自动内存管理需要shutdown ,restart 1.确定sga pga内存大小: 复制代码 代码如下: SHOW PARAMETER TARGET 2.确定自数据库启动以来pga最大的使用大小: 复制代码 代码如下: select value from v$pgastat where name='maximum PGA allocated'; 3.计算memory_target大小: 复制代码 代码如下: memory_target = sga_

  • PHP的垃圾回收机制代码实例讲解

    PHP可以自动进行内存管理,清除不需要的对象,主要使用了引用计数 在zval结构体中定义了ref_count和is_ref , ref_count是引用计数 ,标识此zval被多少个变量引用 , 为0时会被销毁 is_ref标识是否使用的 &取地址符强制引用 为了解决循环引用内存泄露问题 , 使用同步周期回收算法 比如当数组或对象循环的引用自身 , unset掉数组的时候 , 当refcount-1后还大于0的 , 就会被当成疑似垃圾 , 会进行遍历 ,并且模拟的删除一次refcount-1如果

  • jvm垃圾回收算法详细解析

    目录 前言 几种常用的垃圾回收算法 1.引用计数法 2.根搜索算法 3.标记清除法(Mark-Sweep) 4.复制交换算法(Mark-Sweep) 5.标记压缩算法(Mark-Compact) JVM 分代收集算法 前言 相比C语言,JVM虚拟机一个优势体现在对对象的垃圾回收上,JVM有一套完整的垃圾回收算法,可以对程序运行时产生的垃圾对象进行及时的回收,以便释放JVM相应区域的内存空间,确保程序稳定高效的运行,但在真正了解垃圾回收算法之前,有必要对JVM的对象的引用做一个简单的铺垫 JVM对

随机推荐