专业编程教程与实战项目分享平台

网站首页 > 技术文章 正文

前端面试必考知识点,JavaScript性能优化之闭包与内存管理

ins518 2024-10-04 23:59:04 技术文章 15 ℃ 0 评论


从一个for循环开始谈闭包

“麦克,我写了一段代码,但输出结果和我预期的不一致!”小白对着屏幕苦恼

“是吗代码给我看下”


“这是一个很经典的问题。

for循环是同步的,而onclick点击事件是异步触发的,当你点击onclick的时候for循环早就结束了,也就是说i已经是5了。那怎么办呢?你得用闭包啊,我帮你改造一下,我们利用闭包将每次循环的都封闭到一个独立的作用域中”


测试一下!

“果然可以了”小白用chrome浏览器进行了测试


麦克黑继续说道:“关于闭包我们 还可以有另一个种写法。”


测试结果和上次一样。

接下来我给你讲下闭包在开发中的作用和优缺点,你要注意哦,以下内容会在很多前端面试的过程中问到。

闭包在开发中会帮助我们闯到一个封闭的环境变量,避免局部变量暴漏在全局环境下。这样就避免了局部变量对全局的污染。但同时我们也经常会听到的一种说法就是要减少闭包的使用,因为闭包有可能会造成内存泄露。

为什么会造成内存泄露呢?

局部变量在我们使用完退出的时候就会解除对他的引用,然后从内存中推出。但如果使用闭包以后,局部变量就会被封闭在闭包的环境中,那么这个局部变量就会一直存在下去,无法回收,但这并不是内存泄露,仅仅是无法回收而已,如果需要回收,可以通过收到将变量设置为null,就实现了回收.

什么是内存泄露呢?

就比如一杯水,水满了就会溢出。 同理,内存溢出就是程序运行所需的内存大于可用内存,就出现内存溢出错误也叫内存泄露。也就是说如果内存中无法回收的变量过多,就会造成容易造成内存泄露。

容易造成内存溢出的情况

计时器的引用变量没有及时清除,

dom清空或删除时,事件未清除导致的内存泄漏

回调事件造成循环引用导致变量无法被回收

,监听事件没有移出都容易造成内存泄露。

追本溯源,我们先要了解一下JavaScript的内存垃圾回收机制

下面这段话引自《JavaScript权威指南(第四版)》

由于字符串、对象和数组没有固定大小,所有当他们的大小已知时,才能对他们进行动态的存储分配。JavaScript程序每次创建字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。

现在各大浏览器通常用采用的垃圾回收有两种方法

标记清除

这是javascript中最常用的垃圾回收方式。当变量进入执行环境是,就标记这个变量为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到他们。当变量离开环境时,则将其标记为“离开环境”。

  垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后。垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间。

引用计数

不太常见的垃圾回收策略是引用计数。引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数就减1。当这个引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其所占的内存空间给收回来。这样,垃圾收集器下次再运行时,它就会释放那些引用次数为0的值所占的内存。

“那么如何识别自己的内存有没有泄漏呢?”

“最常用的方式就是使用chrome浏览器查看内存占用情况。"

  1. 打开开发者工具,选择 Timeline 面板
  2. 在顶部的Capture字段里面勾选 Memory
  3. 点击左上角的录制按钮。
  4. 在页面上进行各种操作,模拟用户的使用情况。
  5. 一段时间后,点击对话框的 stop 按钮,面板上就会显示这段时间的内存占用情况。

如果内存占用基本平稳,接近水平,就说明不存在内存泄漏。反之,就是内存泄漏了。


注意事项:

虽然有垃圾回收机制但是我们编写代码操作不当还是会造成内存泄漏。

1. 意外的全局变量引起的内存泄漏。

原因:全局变量,不会被回收。

解决:使用严格模式避免。

2. 闭包引起的内存泄漏

原因:闭包可以维持函数内局部变量,使其得不到释放。

解决:将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中,删除对dom的引用。

3. 没有清理的DOM元素引用

原因:虽然别的地方删除了,但是对象中还存在对dom的引用

解决:手动删除。

4. 被遗忘的定时器或者回调

原因:定时器中有dom的引用,即使dom删除了,但是定时器还在,所以内存中还是有这个dom。

解决:手动删除定时器和dom。

5. 子元素存在引用引起的内存泄漏

原因:div中的ul li 得到这个div,会间接引用某个得到的li,那么此时因为div间接引用li,即使li被清空,也还是在内存中,并且只要li不被删除,他的父元素都不会被删除。

解决:手动删除清空


概况总结:

内存泄漏:不再用到的内存没有释放

垃圾回收机制:当该资源的引用数为0,则释放

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表