前端内存泄漏和溢出的情况以及解决办法

这篇具有很好参考价值的文章主要介绍了前端内存泄漏和溢出的情况以及解决办法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

写在前面:

在平时写代码时,内存泄漏的情况会时有发生,虽然js有内存回收机制,但在平时编程中还是需要注意避免内存泄漏的情况;前几天做移动端时遇到一个内存泄漏造成移动端页面卡顿的问题,所以想总结下前端内存泄漏的情况,回顾下基础知识

一、什么是内存泄漏

 程序运行时操作系统会分配相应的内存,如果不进行定时的清理内存的占用情况,内存占用越来越高,很容易造成页面卡顿,进程奔溃;如果程序在系统分配了内存空间后不再使用但是没有及时释放就会造成内存泄漏;程序向系统申请的内存空间超出了系统能给的,就造成了内存溢出。内存泄漏和溢出都会影响程序的性能。

js不需要手动给变量申请内存,当我们在申明一个变量时,js会自动为其分配内存;当某个对象没有被引用会进行回收,最简单的垃圾回收机制是引用计数,当某个对象被引用的次数达到0时就会被回收

二、常见的造成内存泄漏的情况

1.全局变量:一个变量被挂载到window上,那么它永远都是可达的,只有关闭页面或关闭浏览器时被回收。严格模式下可以避免这个情况;解决方法:testVal = null

局部变量:在函数执行过后,局部变量就被回收了,此时便可以将它引用的内存释放掉

另一种全局变量可能由this创建

function foo() {
    this.variable = "potential accidental global";
}
// foo 调用自己,此时this 指向了全局对象(window)
foo();

2.定时器

使用定时器时,我们销毁了这个DOM,但是在定时器中使用了这个DOM,定时器中就保留了对这个DOM的引用,所以需要在清除DOM时也要手动清除定时器(timer = null)

var someResource = getData();
const timer = setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
        // 处理 node 和 someResource
        node.innerHTML = JSON.stringify(someResource));
    }
}, 1000);

解决:document.body.removeChild(node);someResource = null

timer = null ,这样定时器中的node 和someResource才会真的被回收掉

3.闭包函数导致的泄漏

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

function bindEvent() {
  var obj = document.createElement('XXX');
  var unused = function () {
    console.log(obj, '闭包内引用obj obj不会被释放');
  };
  obj = null; // 解决方法
}

4.DOM元素的事件监听

btn.addEventListener('click', onClick)
btn.removeEventListener('click', onClick)

5.没有清理对DOM元素的引用

const refA = document.getElementById('refA');
document.body.removeChild(refA); // dom删除了
console.log(refA, 'refA'); // 但是还存在引用,能console出整个div 没有被回收
refA = null;  // 这里会报错  Assignment to constant variable(赋值给常数变量).因为这个refA是const声明的,值不可以改变,将const改为var
console.log(refA, 'refA'); // 解除引用

三、Vue中占用内存的几种情况

1.全局变量在切换页面时没有清空

mounted() {
      window.test = {
        // 此处在全局window对象中引用了本页面的dom对象
        name: 'home',
        node: document.getElementById('home'),
      }
    },

解决:在页面卸载时顺便清空该引用

destroyed(){

  window.test = null

}

2.监听在window或body上的事件没有解绑

  • 如果在mounted/created 钩子中绑定了DOM/BOM 对象中的事件,需要在beforeDestroy 中做对应解绑处理
  • 如果在mounted/created 钩子中使用了第三方库初始化,需要在beforeDestroy 中做对应销毁处理
  • 如果组件中使用了定时器,需要在beforeDestroy 中做对应销毁处理
  • 某些组件在模板中使用 事件绑定可能会出现泄漏,使用$on 替换模板中的绑定

如果是要render函数,避免在html标签中DOM / BOM事件

mounted () {
  window.addEventListener('resize', this.func)
},
methods:{
    func(){}
}

// 解决:
beforeDestroy () {
  window.removeEventListener('resize', this.func)
}

3.在进入页面时打开弹框dialog,在离开页面时没有设为false

mounted () {
  this.Dialog = true
},

// 在手动点击头部的返回按钮和回到首页的按钮时,会造成页面卡顿,无法滑动的问题

// 在离开页面时将它设为false
  beforeRouteLeave(to, from, next){
    this.Dialog = false
    next()
  },

 4.绑在EventBus的事件没有解绑

解决:页面卸载时解除引用

mounted () {
 this.$EventBus.$on('homeTask', res => this.func(res))
},
destroyed () {
 this.$EventBus.$off()
}

5.v-if指令产生的内存泄漏

在使用v-if来控制显示隐藏的时候,当v-if的条件为false时,浏览器不会渲染这个元素;但是当我们在v-if为true时,给这个元素内添加了其他子元素,那么我们在设为false的时候只是这个父元素本身从虚拟DOM中移除它,新添加的子元素并没有移除,子元素对父元素引用了,父元素也就不会被移除

例子:

<div id="app">
  <button v-if="showChoices" @click="hide">Hide</button>
  <button v-if="!showChoices" @click="show">Show</button>
  <div v-if="showChoices">
    <select id="choices-single-default"></select>
  </div>

原来的写法

<script>
  export default {
    data() {
      return {
        showChoices: true,
      }
    },
    mounted: function () {
      this.initializeChoices()
    },
    methods: {
      initializeChoices: function () {
        let list = []
        // 我们来为选择框载入很多选项,这样的话它会占用大量的内存
        for (let i = 0; i < 1000; i++) {
          list.push({
            label: 'Item ' + i,
            value: i,
          })
        }
        new Choices('#choices-single-default', {
          searchEnabled: true,
          removeItemButton: true,
          choices: list,
        })
      },
      show: function () {
        this.showChoices = true
        this.$nextTick(() => {
          this.initializeChoices()
        })
      },
      hide: function () {
        this.showChoices = false
      },
    },
  }
</script>

处理后的写法:我们在hide方法里移除父元素时对子元素做一个清理

<div id="app">
  <button v-if="showChoices" @click="hide">Hide</button>
  <button v-if="!showChoices" @click="show">Show</button>
  <div v-if="showChoices">
    <select id="choices-single-default"></select>
  </div>
</div>
 
<script>
  export default {
    data() {
      return {
        showChoices: true,
        choicesSelect: null
      }
    },
    mounted: function () {
      this.initializeChoices()
    },
    methods: {
      initializeChoices: function () {
        let list = []
        for (let i = 0; i < 1000; i++) {
          list.push({
            label: 'Item ' + i,
            value: i,
          })
        }
         // 在我们的 Vue 实例的数据对象中设置一个 `choicesSelect` 的引用
        this.choicesSelect = new Choices("#choices-single-default", {
          searchEnabled: true,
          removeItemButton: true,
          choices: list,
        })
      },
      show: function () {
        this.showChoices = true
        this.$nextTick(() => {
          this.initializeChoices()
        })
      },
      hide: function () {
        // 现在我们可以让 Choices 使用这个引用,从 DOM 中移除这些元素之前进行清理工作
        this.choicesSelect.destroy()
        this.showChoices = false
      },
    },
  }
</script>

 6.echart图表带来的内存泄漏

每一个图例在没有数据的时候它会创建一个定时器去渲染气泡,页面切换后,echarts 图例是销毁了,但是这个 echarts 的实例还在内存当中,同时它的气泡渲染定时器还在运行。这就导致 Echarts 占用 CPU 高,导致浏览器卡顿,当数据量比较大时甚至浏览器崩溃。

解决方法:加一个 beforeDestroy()方法释放该页面的 chart 资源,我也试过使用 dispose()方法,但是 dispose 销毁这个图例,图例是不存在了,但图例的 resize()方法会启动,则会报没有 resize 这个方法,而 clear()方法则是清空图例数据,不影响图例的 resize,而且能够释放内存,切换的时候就很顺畅了。

beforeDestroy () {
  this.chart.clear()
}

ES6中防止内存泄漏

在平时编程中我们可能没有及时的清除引用,ES6中新增了两种数据结构:weakset 和 weakmap,他们对值得引用时不计入垃圾回收机制的,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存。

const wm = new WeakMap()
const element = document.getElementById('example')
vm.set(element, 'something')
vm.get(element)

前端排查内存溢出的问题、,性能优化,javascript,开发语言,性能优化

上面代码中,先新建一个 Weakmap 实例。然后,将一个 DOM 节点作为键名存入该实例,并将一些附加信息作为键值,一起存放在 WeakMap 里面。这时,WeakMap 里面对 element 的引用就是弱引用,不会被计入垃圾回收机制。

注册监听事件的 listener 对象很适合用 WeakMap 来实现

<div id="example">点击</div>

// 代码1
element.addEventListener('click', handler, false)
 
// 代码2
const listener = new WeakMap()
listener.set(element, handler)
element.addEventListener('click', listener.get(element), false)

function handler(){
    console.log('测试')
}

好处是:由于监听函数是放在 WeakMap 里面,一旦 dom 对象 ele 消失,与它绑定的监听函数 handler 也会自动消失。

以上总结有些是平时工作中遇到的需要注意的点,有些是借鉴别人的blog:

前端常见内存泄漏及解决方案_傲娇的koala的博客-CSDN博客

 https://mp.weixin.qq.com/s/TEs6JKQsRo2ZbVhVfAuOBA文章来源地址https://www.toymoban.com/news/detail-803957.html

到了这里,关于前端内存泄漏和溢出的情况以及解决办法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Android之内存泄漏与内存溢出

    Android之内存泄漏与内存溢出

    内存泄漏(memory leak):是指程序在申请内存后,无法释放已申请的内存空间,导致系统无法及时回收内存并且分配给其他进程使用。通常少次数的内存无法及时回收并不会到程序造成什么影响,但是如果在内存本身就比较少获取多次导致内存无法正常回收时,就会导致内存

    2024年02月13日
    浏览(11)
  • 性能优化-内存泄漏、内存溢出、cpu占用高、死锁、栈溢出详解

    性能优化-内存泄漏、内存溢出、cpu占用高、死锁、栈溢出详解

    含义:内层泄露是程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费。(换言之,GC回收不了这些不再被使用的对象,这些对象的生命周期太长) 危害:当应用程序长时间连续运行时,会导致严重的性能下降;OOM;偶尔会耗尽连接对象;可

    2024年01月19日
    浏览(15)
  • JavaScript 内存溢出解决办法 亲测有效

    Vue3是一款非常流行的JavaScript框架,它被广泛应用于Web前端开发中。在使用Vue3进行打包时,有时会遇到以下错误信息: “Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory” 这个错误信息意味着JavaScript堆内存不足,导致Vue3打包失败。那么,该怎么解决这

    2024年02月09日
    浏览(7)
  • Java中的内存溢出与内存泄漏深度解析

    目录 引言 一. 内存溢出(Memory Overflow) 1.1 堆内存溢出 1.2 栈内存溢出 1.3 内存溢出的解决策略 1.3.1 优化对象的创建和销毁 1.3.2 调整堆内存大小 1.3.3  使用内存分析工具 1.3.4 避免创建过大的对象 1.3.5 定期清理不再使用的对象 二、 内存泄漏(Memory Leak) 2.1Java内存泄漏的典

    2024年02月19日
    浏览(11)
  • 使用asan检测内存泄漏、堆栈溢出等问题

    操作过程参考:链接 缘起:程序在移动端崩溃,mac端复现不了,于是在写个崩溃位置函数的调用demo,使用ASAN工具进行排查。 验证过程 1、代码 main.cpp 使用附加ASAN工具的方式进行编译: 执行: 没有问题,以上是验证过程,如有问题执行时ASAN会提示有问题的相关位置。 介绍

    2024年02月11日
    浏览(13)
  • 记录--解决前端内存泄漏:问题概览与实用解决方案

    记录--解决前端内存泄漏:问题概览与实用解决方案

    内存泄漏是前端开发中的一个常见问题,可能导致项目变得缓慢、不稳定甚至崩溃。在本文中,我们将深入探讨在JavaScript、Vue和React项目中可能导致内存泄漏的情况,并提供详细的代码示例,以帮助开发人员更好地理解和解决这些问题。 1. 未正确清理事件处理器 JavaScript中的

    2024年02月11日
    浏览(9)
  • ()自定义DialogFragment以及解决其内存泄漏问题

    ()自定义DialogFragment以及解决其内存泄漏问题

    日常开发中,dialog是常见的功能,我们时常需要弹出来一些弹框提示用户 今天就定义了一个方便的dialog基类BaseSimpleDialogFragment, 支持快速地显示一个dialog 主要功能有: initAnimation:设置入场和出场动画 getGravity:设置dialog显示位置(屏幕上,中,下) getCanceledOnTouchOutside:点

    2024年02月15日
    浏览(7)
  • Android TextView动态地加载资源文件,避免Native 层内存泄漏或内存溢出

    在 Android 中,如果使用 TextView 的 setBackgroundResource() 方法设置背景,可能会导致 Native 层内存增长。这是因为 setBackgroundResource() 方法会将资源文件(例如图片)加载到内存中,如果频繁地调用该方法,就会导致内存泄漏或内存溢出。 为了避免这种问题,可以使用 TextView 的 s

    2024年02月09日
    浏览(12)
  • 在线排查内存泄漏的步骤

    在线排查内存泄漏的步骤

    想到内存泄漏问题的排查,很多开发会想到使用 Valgrind。使用 Valgrind 有几个局限: 需要安装 Valgrind 需要启停服务进程 影响服务进程性能 依赖于测试用例覆盖到 BUG 分支 由于这些原因,线上内存泄露问题并不适合用 Valgrind 来排查。相反,利用 top、pmap 等命令,以及 GDB(包括

    2024年02月06日
    浏览(15)
  • 记一次内存泄漏排查

    记一次内存泄漏排查

    最近某项目的服务突然告警,cpu超85%,随后就是服务宕机。交付重启服务后恢复正常但是随后不久又开始告警,特别是白天,严重影响客户业务进行。 1、分析日志 查看日志的过程中发现存在内存溢出(OOM),思考要么存在内存泄漏要么业务上触发了某个接口存在大对象,结

    2023年04月16日
    浏览(13)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包