一张纸搞懂JS系列(3)之垃圾回收机制,内存泄漏,闭包

javascript栏目为大家介绍垃圾回收机制内存泄漏闭包的内容,快端小板凳来看看啦。

一张纸搞懂JS系列(3)之垃圾回收机制,内存泄漏,闭包

写在最前面:这是javascript栏目我即将开始写的一个系列,主要是在框架横行的时代,虽然上班用的是框架,但是对于面试,以及技术进阶,JS基础知识的铺垫是锦上添花,也是不得不学习的一块知识,虽然开汽车的不需要很懂汽车,只需要掌握汽车的常用功能即可。但是如果你懂汽车,那你也能更好地开车,同理。当然,一篇文章也不会光光只讲一个知识点,一般会将有关联的知识点串联起来,一边记录自己的学习,一边分享自己的学习,互勉!如果可以的话,也请给我点个赞,你的点赞也能让我更加努力地更新!

概览

食用时间: 6-12分钟难度: 简单,别跑,看完再走

垃圾回收机制

前面一篇博客主要讲解了内存的分配和使用(栈内存与堆内存,深拷贝与浅拷贝),使用完了以后,当然是要将不使用的内存归还,就像将手机上不使用的软件从后台清除,可以提升手机的运行速度,不然越来越多,迟早会卡, JS 也是一样的。

每隔一段时间, JS 的垃圾收集器都会对变量进行“巡逻”,就和保安巡逻园区一样,让不相干的人赶紧走。当一个变量不被需要了以后,它就会把这个变量所占用的内存空间所释放,这个过程就叫做垃圾回收

JS 的垃圾回收算法分为两种,引用计数法和标记清除法

引用计数法

引用计数法是最初级的垃圾回收算法,已经被现代浏览器所淘汰了。在学习引用计数法之前,需要首先对引用有一定的概念,你可以认为它就是对当前变量所指向的那块内存地址的描述,有点类似于JS引用数据类型的内存指向的概念,先来看一行代码:

var obj={name:'jack'};复制代码

登录后复制

当我们在给 obj 赋值的同时,其实就创建了一个指向该变量的引用,引用计数为1,在引用计数法的机制下,内存中的每一个值都会对应一个引用计数

而当我们给 obj 赋值为 null时,这个变量就变成了一块没用的内存,那么此时, obj 的引用计数将会变成 0,它将会被垃圾收集器所回收,也就是 obj 所占用的内存空间将会被释放

我们知道,函数作用域的生命周期是很短暂的,在函数执行完毕之后,里面的变量基本是没用的变量了,不清除的后果就是该内存垃圾没有被释放,依然霸占着原有的内存不松手,就会容易引发内存泄漏,先来看一段代码以及运行结果:

function changeName(){   var obj1={};   var obj2={};      obj1.target=obj2;   obj2.target=obj1;   obj1.age=15;   console.log(obj1.target);   console.log(obj2.target);}changeName();复制代码

登录后复制

一张纸搞懂JS系列(3)之垃圾回收机制,内存泄漏,闭包

我们可以看到, obj1.target 和 obj2.target 存在互相引用的情况,因为在改变 obj1.age 的同时,obj1.target.age 和 obj2.target.age 也同时都被影响到了,它们所指向的引用计数是一致的

在函数执行完毕的时候, obj1 和 obj2 还是活的好好地,因为 obj1.target 和 obj2.target 的引用计数在执行完毕之后,仍然是 1 ,明明函数执行完毕,但是这种垃圾依然存在,这种函数定义多了,内存泄漏也会是无法避免的

标记清除法

上面的引用计数法的弊端已经很明显了,那么,现在所要说的标记清除法就不存在这样子的问题。因为它采用的判断标准是看这个对象是否可抵达,它主要分为两个阶段,标记阶段清除阶段:

标记阶段

垃圾收集器会从根对象(Window对象)出发,扫描所有可以触及的对象,这就是所谓的可抵达

清除阶段在扫描的同时,根对象无法触及(不可抵达)的对象,就是被认为不被需要的对象,就会被当成垃圾清除

现在再来看下上面的代码

function changeName(){    var obj1={};  var obj2={};    obj1.target=obj2;  obj2.target=obj1;  obj1.age=15;  console.log(obj1.target);  console.log(obj2.target);}changeName();复制代码

登录后复制

在函数执行完毕之后,函数的声明周期结束,那么现在,从 Window对象 出发, obj1 和 obj2 都会被垃圾收集器标记为不可抵达,这样子的情况下,互相引用的情况也会迎刃而解。

内存泄漏

该释放的内存垃圾没有被释放,依然霸占着原有的内存不松手,造成系统内存的浪费,导致性能恶化,系统崩溃等严重后果,这就是所谓的内存泄漏

闭包

定义与特性

闭包是指有权访问另一个函数作用域中的变量的函数。至于为什么有权访问,主要是因为作用域嵌套作用域,也就是所谓的作用域链,关于作用域链不清楚的可以看我的第一篇博客一文搞懂JS系列(一)之编译原理,作用域,作用域链,变量提升,暂时性死区,就是因为作用域链的存在,所以内部函数才可以访问外部函数中定义的变量 ,作用域链是向外不向内的,探出头去,向外查找,而不是看着锅里,所以外部函数是无法访问内部函数定义的变量的。并且,还有一个特性就是将闭包内的变量始终保持在内存中。

前面的作用域向外不向内,这里就不再做过多解释了,我们主要来看我后面说的特性,那就是闭包内的变量始终保存在内存中

来看一下阮一峰教程当中的一个例子

 function f1(){     var n=999;     nAdd=function(){n+=1}     function f2(){         console.log(n);     }     return f2; } var result=f1();     //等同于return f2(); result(); // 999 nAdd(); result(); // 1000 nAdd(); result(); // 1000复制代码

登录后复制

从输出结果就可以看得出来,这个变量 n 就一直保存在内存中,那么,为什么会这样子呢,我们现在就来逐步地分析代码

① 首先 f1() 作为 f2() 的父函数,根据作用域链的规则, nAdd() 方法以及 f2() 方法中可以正常访问到 n 的值

② f2() 被赋予了一个全局变量,可能这里大家就会开始产生疑惑了,这个 f2() 不是好好地定义在了 f1() 函数中吗,这不是扯淡吗,那么,先看下面的这句 var result=f1(); ,这个 result 很明显是被赋予了一个全局变量,这应该是没有任何争议的,那么,接着来看这个 f1() ,可以看到最后,是一句 return f2; ,看到这里,想必大家也已经想明白了,这个 f2() 被赋予了一个全局变量

③ 已经明白了上面的这一点以后,根据上面垃圾回收机制所提及到的标记清除法,这个 f2() 始终是可以被根对象 Window 访问到的,所以 f2 将始终存在于内存之中,而 f2 是依赖于 f1 ,因此 f1 也将始终存在于内存当中,那么, n 的值也就自然始终存在于内存当中啦

④ 还有一点需要注意的就是为什么我们可以直接执行 nAdd() ,这是因为在 nAdd() 的前面没有使用 var ,因此 nAdd() 是一个全局函数而不是局部函数

所以,闭包的变量会常驻内存,滥用闭包容易造成内存泄漏,特别是在 IE 浏览器下,2020年了,应该没人使用 IE 了吧(小声bb),解决办法就是在退出函数之前,将不使用的局部变量全部删除,这也是上面讲了垃圾回收机制 => 内存泄漏,再讲到闭包的原因,我会尽量将有关联性的知识点一起讲了,也方便大家学习和加深印象。

系列目录

一张纸懂JS系列(1)之编译原理,作用域,作用域链,变量提升,暂时性死区

一张纸搞懂JS系列(2)之JS内存生命周期,栈内存与堆内存,深浅拷贝

一张纸搞懂JS系列(3)之垃圾回收机制,内存泄漏,闭包

相关免费学习推荐:javascript(视频)

以上就是一张纸搞懂JS系列(3)之垃圾回收机制,内存泄漏,闭包的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2725422.html

(0)
上一篇 2025年3月7日 23:23:06
下一篇 2025年3月6日 16:41:18

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • JavaScript 来好好盘一盘闭包!

    今天JavaScript栏目好好介绍闭包。 前言 想要深入学习JavaScript这门语言,闭包这个概念几乎是绕不开的关键,今天就让我们一起好好地盘一盘,闭包到底是什么东西。如果是零基础的小伙伴,可以先看看前一篇文章,帮助你更好的理解本文的…

    2025年3月7日
    200
  • 了解JavaScript中的垃圾回收机制

    推荐教程:《JavaScript视频教程》 最近看到一些面试的回顾,不少有被面试官问到谈谈JS 垃圾回收机制,说实话,面试官会问这个问题,说明他最近看到一些关于 JS 垃圾回收机制的相关的文章,为了 B 格,就会顺带的问问。 最近看到一篇讲…

    2025年3月7日 编程技术
    200
  • JavaScript常见几种的内存泄漏

    javascript栏目教程介绍常见的内存泄漏。 前言1 介绍2 内存泄露的主要原因3 常见的内存泄露3.1 全局变量3.2 计时器3.3 多处引用3.4 闭包4 Chrome内存分析工具资料 前言 在阅读这篇博客之前,你或许需要具备一些J…

    2025年3月7日
    200
  • 详解JS中的垃圾回收和内存泄漏

    程序的运行需要内存。只要程序提出要求,操作系统或者运行时就必须供给内存。所谓的内存泄漏简单来说是不再用到的内存,没有及时释放。为了更好避免内存泄漏,我们先介绍Javascript垃圾回收机制。 在C与C++等语言中,开发人员可以直接控制内存…

    2025年3月7日 编程技术
    200
  • 介绍JavaScript作用域和闭包

    免费学习推荐:javascript视频教程 JavaScript作用域和闭包 在javascript中,如果对作用域和闭包弄不清楚,写代码就会出很多问题,今天对作用域和闭包做一个总结。 作用域 立即学习“Java免费学习笔记(深入)”; 作…

    2025年3月7日
    200
  • 理解Javascript中的Closure(闭包)

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。 一、变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域。 变量的作用域无非就是两种:全局变量和局部变量。 立即…

    2025年3月7日
    200
  • 7个JavaScript中关于闭包的面试题,你能回答上来吗?

    相关推荐:2021年大前端面试题汇总(收藏) 每个 JavaScript 程序员都必须知道闭包是什么。在 JavaScript 面试中,你很可能会被问到闭包的概念。 以下是 7 个有关 JavaScript 闭包的面试题,比较有挑战性。 不…

    2025年3月7日
    200
  • 什么是闭包?聊聊javascript中闭包,看看闭包有哪些作用?

    什么是闭包?看看闭包有哪些作用?下面本篇文章带大家聊聊javascript中闭包。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 在前端学习的过程中,我们难免会遇到许许多多的问题,那么今天我们来以一个初学者的角度来谈谈两个…

    2025年3月7日
    200
  • 深入浅析JS中的垃圾回收机制

    基本类型存放在栈中,引用类型存放在堆中。javascript 是在创建变量(对象,字符串等)时自动进行了分配内存,并且在不使用它们时“自动”释放。释放的过程称为垃圾回收。 垃圾回收策略 所有垃圾回收器都需要做的任务 标记空间中活动(存活)对…

    2025年3月7日 编程技术
    200
  • 一文详解JavaScript中的闭包

    javascript 闭包是一种重要的概念,在 javascript 编程中被广泛使用。尽管它可能会让初学者感到困惑,但它是理解 javascript 语言核心的关键概念之一。本文将深入探讨 javascript 闭包,让你了解它是如何工作…

    2025年3月7日
    200

发表回复

登录后才能评论