js---js使用闭包是否会产生内存泄露及解决方案

2023-11-20

一、前置知识

闭包的产生

js垃圾回收机制

不懂的可以先移步到下方的博客再回来

「前端进阶」JS中的内存管理 - 知乎

二、闭包是否会产生内存泄露

在此强调变量arr保存的是对引用数据类型数组的引用(地址),保存在中;数组的每一项值保存在中,new Array(10000000)大约占据40mb内存

案例1:

    function fn() {
      //fn函数作用域的局部变量arr
      const arr = new Array(10000000)
      function fn1() {
        // 在fn1函数作用域下访问(依赖)外层fn函数作用域的局部变量arr,此时会产生闭包
        console.log(arr[0]);
      }
      fn1()
    }
    fn()

打开控制台进行断点查看:

打开控制台进行性能分析: 

 ps:函数在执行时一开始由于创建了new Array(10000000),所以占据了堆中大概40mb内存,也就是一个Array(10000000)的大小,不过在很快的一段时间内变为了1.3mb,也就是js的垃圾回收机制在闭包函数运行后成功后在一段时间后把闭包产生的内存垃圾(new Array(10000000))给清理掉了

案例二:

    function fn() {
      const arr = new Array(10000000)
      function fn1() {
        console.log(arr[0]);
      }
      return fn1
    }
    fn()()

打开控制台进行断点查看:

打开控制台进行性能分析: 

 ps:跟案例1一样,不会造成内存浪费,不多加解释

案例3:


    function fn() {
      const arr = new Array(10000000)
      function fn1() {
        console.log(arr[0]);
      }
      return fn1
    }
    //变量test由于保存了fn1函数的引用,而fn1函数作用域内又依赖于fn作用域的Array(10000000),
    // 所以导致Array(10000000)在堆内存中无法被释放
    let test = fn()
    test()

打开控制台进行断点查看: 

 打开控制台进行性能分析: 

ps:

js垃圾回收机制的一个算法是标记清除法:

  一、即能被标记的到的变量,说明变量可能会在某一个时间点需要用到,所以垃圾回收机制不会将该变量进行回收,一直存放在内存中,直到页面浏览器的关闭,变量才会被释放

二、就比如像全局作用域下的变量,整个代码线程运行过程中,全局变量都存在于内存中,因为全局变量不知道在什么时候会再次使用,所以js会使用(window.全局变量)对全局变量进行标记,所以对标记到的全局变量不会进行回收

①在本案例中闭包函数运行时由于创建了 new Array(10000000),所以占据了堆中大概40mb内存,再有全局变量test由于保存了fn1函数的引用,而fn1函数作用域内又依赖于fn作用域的Array(10000000),导致js垃圾回收机制通过全局变量test---》fn1函数---》Array(10000000),从而找到Array(10000000)进行标记,所以js不会对存在堆内存的中Array(10000000)进行回收,导致堆内存中的Array(10000000)(40mb)一直无法释放。从而造成内存浪费。

解决方案:

通过设置变量为null将标记链断开,修改本案例如下:


    function fn() {
      const arr = new Array(10000000)
      function fn1() {
        console.log(arr[0]);
      }
      return fn1
    }
    //变量test由于保存了fn1函数的引用,而fn1函数作用域内又依赖于fn作用域的Array(10000000),
    // 所以导致Array(10000000)在堆内存中无法被释放
    let test = fn()
    test()
    test = null

 ps:通过将全局变量test的值设为null,全局变量test无法再依赖fn1函数---》Array(10000000),从而无法对Array(10000000)进行标记,所以js会对存在堆内存的中Array(10000000)进行回收,导致堆内存中的Array(10000000)(40mb)释放。不会造成内存浪费。

案例4:

    function fn() {
      const arr = new Array(10000000)
      function fn1() {
        console.log(arr[0]);
        return new Array(10000000)
      }
      return fn1
    }
    let test = fn()
    let arr = test()

  打开控制台进行性能分析:

ps:80mb大概就是两个 Array(10000000)的内存大小,因为全局变量test,arr一直保持对Array(10000000)的引用,所以导致js垃圾回收机制无法回收,

解决方案:

设置变量设置为null

    function fn() {
      const arr = new Array(10000000)
      function fn1() {
        console.log(arr[0]);
        return new Array(10000000)
      }
      return fn1
    }
    let test = fn()
    let arr = test()
    test = null
    arr = null

   打开控制台进行性能分析:

ps:经过设置变量为null,从而将内存浪费进行释放 

三、总结

1.使用闭包是否一定会产生内存浪费吗?

答:不一定,闭包是否产生内存浪费取决于js的垃圾回收机制是否将变量占用的内存给及时清除掉,常见的垃圾回收算法有标记清除法,能标记到就不回收,反之则回收。一般如果闭包函数没有返回值或者没有使用全局变量对闭包函数的返回值进行存储,那么是不会造成内存浪费的,详见文章的案例1和案例2;而如果闭包函数存在返回值并且使用全局变量对闭包函数的返回值进行存储,那么可能会造成内存浪费的,详见案例3和案例4

2.如何解决闭包产生的内存浪费

通过设置变量为null即可间接或直接释放内存浪费,变量使用完毕后及时设置为null即可

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

js---js使用闭包是否会产生内存泄露及解决方案 的相关文章

  • 悬停此元素时隐藏元素后的伪元素

    我的菜单垂直放置在页面左侧和菜单之间 li 我有一个 after那是一个分隔符 我想要的是当我悬停元素本身 如果它是第一个元素 时隐藏 after 元素 或者当它是中间元素时隐藏上面和底部的元素 如果它是最后一个子元素 则隐藏 after前
  • 最大宽度调整以适应文本?

    不是最好的标题 但无论如何 我有一个元素max width和一些文字 如果文本长度超过一行所能容纳的长度 我会得到以下结果 My text here hello everyone 换句话说 它占据了完整的最大宽度 但由于单词向下移动 右侧有
  • 使用 dc.js 按条形值对条形图中的条形进行排序(排序)

    如何通过维度的计算值而不是维度本身的名称对 dc js 示例中的 x 轴 维度 进行排序 例如 请考虑序数条形图的 dc js 示例 https github com dc js dc js blob master web examples
  • 有没有办法使用 Rspec/Capybara/Selenium 将 javascript console.errors 打印到终端?

    当我运行 rspec 时 是否可以让 capybara selenium 向 rspec 报告任何 javascript console errors 和其他异常 我有一大堆测试失败 但当我手动测试它时 我的应用程序正在运行 如果不知道仅在
  • Angular - CSS - 自定义类型=文件输入,如何使用按钮而不是标签?

    我制作了一个类型为 file 的自定义输入字段 因为我不喜欢默认的输入字段 为了实现这一目标 我做了
  • 将 GMT 时间转换为当地时间

    我以这种格式从我的服务器获取 GMT 时间 Fri 18 Oct 2013 11 38 23 GMT 我的要求是使用Javascript将此时间转换为本地时间 例如 如果用户来自印度 首先我需要采用时区 5 30并将其添加到我的服务器时间并
  • 为什么 IE8 在我的图像锚标记上添加底部边框?

    我知道 这很可悲 但今天早上 IT 刚刚在我的机器上安装了 IE8 我立刻遇到了一个明显的问题 尽管我知道答案就在我面前 但我已经把它搞砸了太久了 首先 这是网站 www mchenry edu http www mchenry edu 在
  • 为 Angular2 中的组件加载多个样式表

    我正在构建一个 angular2 应用程序 当我尝试为同一组件加载多个样式表时 我面临多个问题 这是我正在做的代码 import Component from angular core Component selector my tag t
  • Firefox 不会在使用 jQuery AJAX 加载的内容上呈现 CSS 样式

    我有一个网站 允许用户对书籍和文章发表评论 主表单有一个搜索输入 用于查找相关书籍或文章 来源 我使用 jQuery 根据输入的搜索词从外部站点动态加载新源 然后还使用 AJAX 返回列表中的源 我有两个问题 现在 在用户输入四个字符后 j
  • 检查 jQuery 1.7 中是否存在基于文本的选择选项

    所以我有以下 HTML 片段
  • window.location 和 location.href 之间的区别

    我对之间的区别感到困惑window location and location href 两者似乎都以相同的方式行事 有什么不同 window location是一个对象 它保存有关当前文档位置的所有信息 主机 href 端口 协议等 lo
  • 将 UMD Javascript 模块导入浏览器

    你好 我正在对 RxJS 进行一些研究 我可以通过在浏览器中引用它来使用该库 如下所示 它使用全局对象命名空间变量 Rx 导入 我可以制作可观察的东西并做所有有趣的事情 当我将 src 更改为指向最新的 UMD 文件时 一切都会崩溃 如下所
  • Three.js 各种大小的粒子

    我是 Three js 的新手 正在尝试找出添加 1000 个粒子的最佳方法 每个粒子都有不同的大小和颜色 每个粒子的纹理是通过绘制画布创建的 通过使用粒子系统 所有粒子都具有相同的颜色和大小 为每个粒子创建一个粒子系统是非常低效的 有没有
  • 使用css bootstrap时如何仅向一列添加右边框?

    我正在尝试使用CSS引导框架 http getbootstrap com css tables在我的项目中 我正在使用带有以下类的表table table bordered table striped 我想删除除第一列之外的所有列的边框 这
  • 如何隐藏/禁用 Highcharts.js 中的图例框?

    我想问是否可以使用 HighCharts js 库隐藏图表中的所有图例框 var chart object chart renderTo render to type graph type colors graph colors title
  • 带参数的事件监听器

    我想将参数传递给 JavaScript 中的事件侦听器 我已经找到了解决方案 但我无法理解它们为什么或如何工作以及为什么其他解决方案不起作用 我有 C C 背景 但是 Javascript 函数的执行有很大不同 您能否帮助我理解以下示例如何
  • 用于交互式图形绘制的轻量级 JavaScript 库? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有兴趣了解用于绘制交互式图表的最轻量级 javascript 库 我掌握的数据主要是与海洋研究相关的科学数据 我知道一些 jquery
  • 如何用另一个响应替换窗口的 URL 哈希?

    我正在尝试使用替换方法更改哈希 URL document location hash 但它不起作用 function var anchor document location hash this returns me a string va
  • 在 CKEditor 中设置字体大小和字体系列

    我正在使用 ckeditor 我想问一下这个插件如何设置font family和font size 我尝试过使用 CKEDITOR config font defaultLabel Arial CKEDITOR config fontSiz
  • CSS溢出文本显示在几行中,没有断字

    我有一些长文本显示在 div 中 该 div 具有固定的宽度和高度 我希望文本显示在几行上 作为 div 高度 并且句子单词不会中断 一行中的单词前缀和下一行中的继续 此外 我想在末尾添加省略号最后一句话 CSS white space n

随机推荐