美文网首页
记录一次定时器及闭包问题造成的内存泄漏

记录一次定时器及闭包问题造成的内存泄漏

作者: LinDaiDai_霖呆呆 | 来源:发表于2019-10-01 09:12 被阅读0次

前言

这是一篇记录工作上所遇到的关于内存泄漏问题及如何解决的文章。

问题描述

先大概描述一下我的问题:

技术栈: 框架:vue 组件库: ant design of vue 图表:g2.

项目需求: 在下图的看板中, 需要每20秒切换一次下面的两个小蓝点, 以达到切换并刷新图表的功能.前提是不用web socket等轮询工具.

下图的组件结构:
switch-flex-chart 组件由 flex-chart 组件和 switch-icon-card 两个组件组合而成, 我通过给switch-icon-card 组件(也就是两个小蓝点) 添加一个定时器, 每20秒改变一下index,并且回调给父组件 (switch-flex-chart) 然后刷新并改变 flex-chart 组件里的图表数据.

img

造成的问题: 刚开始还好,但是如果时间久了,就会造成页面非常的卡顿, 可是在代码中, 我在生命周期-销毁阶段的里每次都会把定时器给清除并置为null

一、定时器要及时清除

这里轮询的功能我没有使用setInterval,而是使用了两个setTimeout

<template></template>

<script>
export default {
  created() {
        this.init()
  },
  mounted() {},
  data() {
    return {
        duration: 20000, // 多久刷新一次
        _timer: null // 定时器
    }
  },
  methods: {
    init () { // 初始化
        if (this.duration > 0) {
          this._timer && clearTimeout(this._timer)
          this._timer = null
          this.polling()
        }
    },
    autoPlay () { // 切换的函数
        ...
    },
    polling () {
        this._timer = setTimeout(() => {
          this.autoPlay()
          this._timer && clearTimeout(this._timer)
          this.polling() // 循环调用自身
        }, this.duration)
    }
  }
}
</script>

如上面的代码,我在每次轮询polling的时候,都会使用clearTimeout来清除一下定时器,但是我发现在你切换到其他页面的时候,定时器还是在默默地执行着,于是我想到了在组件每次销毁的时候也必须把定时器也销毁:

destroyed() { // 生命周期-组件销毁
    this._timer && clearTimeout(this._timer) // 先使用clearTimeout
    this._timer = null // 最好将定时器也设置为null
}

二、图表数据及时清空

上面的方式解决了切换页面定时器还在运行的问题,但是还是没有解决页面会很卡顿的情况。正常来说就算定时器跑的再久也不会有这个问题。所以肯定是有哪里造成了内存泄漏。

为了验证是不是这个原因,我打开了chromeF12控制台。然后找到了Memory

memory

在这里你可以记录JavaScript对象的堆快照,查找到内存泄漏。

此时我每10秒录制一个快照,分别对应Snapshot1-3,发现JavaScript对象的总大小一次比一次大,要不了一会我的浏览器就卡的不行了。

堆快照

首先我想到的是不是图表内容没有清空,所以我在每次绘制g2图表的时候先执行了一遍g2内置的方法destory()进行销毁。

<template></template>

<script>
export default {
  created() {
        this.init()
  },
  mounted() {},
  data() {
    return {
        chart: null
    }
  },
  methods: {
      init () {
        if(this.chart){ // 如果存在的话就销毁图表再重新生成
          this.chart.destroy()
        }
        this.chart = new G2.Chart({
            ...
        })
      }
  }
</script>

以为大功告成的我再次打开浏览器,发现内存泄漏的问题并没有解决。于是我想这个图表对象是不是也要像定时器一样,在销毁的时候释放内存呢?

动手试试:

destroyed () {
    this.chart.destroy()
    this.chart = null
}

处理完之后,我再次录制了三个快照,这次JavaScript对象的大小没有再增长了,并且我页面挂在那半个小时也丝毫没有卡顿的迹象。

后记

虽然问题解决了,但我还不是很清楚,为什么在初始化的时候使用this.chart.destroy()不能够释放内存,而非要使用设置成null的方式。Googleg2destory()之后也是蹦出了一堆LOL里的G2...

在此也要感谢 OBKoro1 的倾囊相助。

参考文章:

谈一谈我在前端开发的时候遇到的过的内存泄漏

JS高程中的垃圾回收机制与常见内存泄露的解决方法

相关文章

  • 记录一次定时器及闭包问题造成的内存泄漏

    前言 这是一篇记录工作上所遇到的关于内存泄漏问题及如何解决的文章。 问题描述 先大概描述一下我的问题: 技术栈: ...

  • iOS内存泄漏易错点

    问题 记录一个内存泄漏的案例,闭包引用自己或者多个对象,导致对象无法正常销毁,从而导致内存泄漏。 上面例子的闭包中...

  • 什么是闭包?闭包的好处是什么?

    什么是闭包,闭包的好处 闭包 : 再函数外部可以访问函数内部的变量 好处: 坏处: 容易造成内存泄漏 闭包的相关应...

  • 闭包

    闭包:外层函数能够访问内层变量的函数,缺点就是容易造成内存泄漏。

  • 闭包的作用

    闭包:内部函数保存到外部 当内部函数被保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放,造成内存泄漏(内存...

  • 内存泄漏处理

    全局变量 定时器和回调函数 闭包 4.dom泄漏 console.log引起的内存泄漏 5.echarts引起的内...

  • JS中闭包以及垃圾回收机制

    闭包 闭包是指一个函数可以访问另一个函数中的变量。 常见的形式:函数里嵌套函数。 缺点:大量使用闭包会造成内存泄漏...

  • *闭包(上)与立即执行函数[JavaScript_007]

    闭包 定义 :内部函数被保存到外部,将生成闭包 危害 :导致原有作用域链不释放,造成内存泄漏 作用实现公有变量 此...

  • swift函数赋值给闭包引起的循环引用

    swift的闭包就类似oc中的block回调,使用的过程中可能会引起循环引用,从而造成内存泄漏。这里记录之前公司项...

  • 闭包不会造成内存泄漏哦!

    昨天晚上上了网易前端微专业的第一次直播课,感觉非常好,老师也普及了一个之前面试经常会被问到的问题——闭包。并且老师...

网友评论

      本文标题:记录一次定时器及闭包问题造成的内存泄漏

      本文链接:https://www.haomeiwen.com/subject/cplkpctx.html