内存泄漏问题想必大家够遇见过,但是怎么才能去预防或者说遇到的时候怎样去处理呢?
什么是内存泄漏
程序在运行时候需要操作系统为其分配内存。对于持续运行的服务进程(daemon),必须及时释放不再用到的内存,轻则影响系统性能,重则导致进程崩溃。
有些语言(比如 C 语言)必须手动释放内存,程序员负责内存管理。
char * buffer;
buffer = (char*) malloc(42);
// Do something with buffer
free(buffer);
上面是 C 语言代码,malloc方法用来申请内存,使用完毕之后,必须自己用free方法释放内存。
这很麻烦,所以大多数语言提供自动内存管理,减轻程序员的负担,这被称为"垃圾回收机制"(garbage collector)
js常见的内存泄漏
- 全局变量引起的内存泄漏
function leaks(){
leak = '***'; //leak 成为一个全局变量,不会被回收
}
- 闭包引起的内存泄漏
var leaks = (function(){
var leak = '***';// 被闭包所引用,不会被回收
return function(){
console.log(leak);
}
})()
- dom清空或删除时,事件未清除导致的内存泄漏
document.querySelector("#demo").addEventListener('click', myFunction);
var para1=document.querySelector("#demo");
para1.parentNode.removeChild(para1);
如果我们在没有取消 click 方法前去销毁了 para1 节点,就会造成内存泄露。
正确做法
document.querySelector("#demo").addEventListener('click', myFunction);
// 我们需要在删除节点前清除挂载的 click 方法
document.querySelector("#demo").removeEventListener("click", myFunction);
var para1=document.querySelector("p1");
para1.parentNode.removeChild(para1);
例子:
关键代码:
子组件
class StoreCard extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true
}
}
componentDidUpdate() {
this.state.loading = true;
}
render() {
const dataAll = ClassStore[this.props.data.key].data[this.props.data.item].dataAll;
//...............................注意...........................
setTimeout(e => {
this.state.loading = false
this.forceUpdate();
}, 1000)
//...............................注意...........................
return dataAll.length ? <PageData data={dataAll} loading = {this.state.loading} />:<Empty description={false} />
}
}
export default StoreCard;
父组件:
//省略.............................................................
.........................................
const routeMap = {}
const currentPage = document.location.hash.replace(/#\/?/, "");
const CurrentPage = routeMap[currentPage] || StoreCard;
........................................................
//引用子组件
function SiderPage(props) {
return (
<Layout style={{ padding: '0 24px 24px' }}>
<Content
style={{
background: '#fff',
padding: 24,
margin: 10,
minHeight: 280,
}}
>
<CurrentPage data={props.data} />
</Content>
</Layout>
);
}
//省略............................................................
//存在一个页面跳转
function HeaderIndex() {
return (
<Header className="header">
<div className="title-logo">
..............................................................
<Menu.Item key="1">
<Link to="/login">你好!请登录 </Link>
</Menu.Item>
<Menu.Item key="2">免费注册</Menu.Item>
..............................................................................
</Header>
);
}
原因:因为子组件之中存在一个settimeout,并没有在组件卸载前被清除,这个时候导致内存泄漏而报错…
解决办法:
在卸载之前清除settimeout
class StoreCard extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true
}
}
componentDidUpdate() {
this.state.loading = true;
}
//..............................增加...........................
componentWillUnmount(){
clearTimeout(this.loadTime);
}
//...............................增加..........................
render() {
const dataAll = ClassStore[this.props.data.key].data[this.props.data.item].dataAll;
//...............................修改...........................
this.loadTime = setTimeout(e => {
this.state.loading = false
this.forceUpdate();
}, 1000)
//...............................修改...........................
return dataAll.length ? <PageData data={dataAll} loading = {this.state.loading} />:<Empty description={false} />
}
}
export default StoreCard;
成功解决!!!
扩展: Chrome 怎样去识别内存泄漏
扩展阅读
1、《promise 请求是否会造成内存泄露》Does never resolved promise cause memory leak?
Does never resolved promise cause memory leak?
2、《循环一个 promise 造成内存泄露?》Memory leaks in loops with Promise ?
3、《常见setState的原理解析》