系统进程不再用到的内存,没有及时的释放,就叫做内存泄漏。
由于js对没有进行申明的变量会默认是在全局变量上定义的,而系统的全局变量是 window,只有关闭窗口和刷新页面,全局变量才会被释放,如果在一个没有声明的变量上保存了大量的数据,这些数据就会保存在全局变量上,当这些数据没有及时的被回收,就会发生 内存泄漏。
- 没有声明的变量
function fn(){ a='hello' } fn();
- 使用this申明的变量
function fn(){ // 这里的this指向它的调用者,他的调用者是window this.a='hello'; } fn()
解决方法:
避免使用没有声明的变量;
使用 严格模式,在js文件头部或者是函数首行使用严格模式
由于闭包可以访问函数内部的变量,让这些变量一直保存在内存中,如果没有及时的清理掉这些变量,就会发生内存泄漏。
function fn(){ var a='i am a'; return function(){ console.log(a); } }
解决方法:将事件处理程序定义在函数的外部
// bad for(var k=0;k<10;k++){ var t=function(a){ console.log(a) } t(k) } // good function t(a){ console.log(a) } for(var k=0;k<10;k++){ t(k) } t=null
虽然在别的地方Dom别删除了,但是对象对这个Dom元素的引用并没有被删除
var element={ btn:document.getElementById('btn') } function doSomeThing(){ element.btn.cilck() } function removeClick(){ // 虽然移除了dom中的btn元素,但是对象中对btn的引用还是没有被删除 document.body.removeChild(document.getElementById( 'btn' ))
解决方法:将element.btn=null
定时器中有dom的引用,即使dom删除了,但是定时器还在,所以内存中还是会有这个dom。
// 定时器模式 var data=load() setTimeout(() => { var text=document.getElementById('text') if(text){ text.innerHtml=JSON.stringify(data) } }, 5000); // 观察者模式 var btn=document.getElementById('btn') function click(element){ element.innerHtml='hello' } btn.addEventListener("click",click);
解决方法:
- 手动删除定时器和dom
- 添加removeEventListener
使用VUE开发的SPA应用,更需要关注内存泄漏,因为VUE项目是不会刷新页面的,所以 Vue 应用需要自行清理组件来确保垃圾回收以预期的方式生效。
全局变量在页面切换的时候没有被清空。
export default { mounted() { window.test = { // 此处在全局window对象中引用了本页面的dom对象 name: home , node: document.getElementById( home ), } }, }
解决方法:在页面卸载的时候就将全局变量被清空
特别注意window.addEventListener之类的事件监听
<template> <div id='home'>这里是首页</div> </template> <script> export default{ mounted(){ window.addEventListener(resize,this.func) // window对象调用了home页面的方法 } } </script>
解决方法:在页面销毁的时候,顺便解除应用,释放内存
mounted(){ window.addEventListener(resize,this.func) } beforeDestory(){ window.removeEventListener(resize,this.func) }