【JavaScript编程】内存泄漏

内存泄漏


定义

程序的运行需要内存,对于持续运行的服务进程,必须及时释放不再用到的内存。不再用到的内存,没有及时释放,就叫做内存泄漏。

影响

内存如果没有及时释放,占用就会越来越高,轻则影响系统性能,重则导致进程崩溃。

如何规避
  1. 垃圾回收机制
  2. 规范代码(手动释放等)
  3. 内存检查

一、垃圾回收机制


定义

有些语言(比如 C 语言)必须手动释放内存,程序员负责内存管理。这很麻烦,所以大多数语言提供自动内存管理,减轻程序员的负担,这被称为"垃圾回收机制"。

垃圾回收器

垃圾回收器会定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),那么该对象的内存即可回收。

局限性

并不是说有了垃圾回收机制,就可以当甩手程序员了。你还是需要关注内存占用:
那些很占空间的值,一旦不再用到,你必须检查是否还存在对它们的引用。如果是的话,就必须手动解除引用


二、如何避免内存泄漏


在编程过程中,有很多操作会导致内存泄漏,下面是常见的泄漏情景以及如何规避。

1、全局变量

全局作用域要等进程全部退出才会释放,此时将会导致引用的对象常驻内存。

  • 要避免意外的全局变量(使用 严格模式代码规范工具 ESlint)。

    function fn() { 
        a = "全局变量"; // 等同于 window.a = "全局变量"
    }
    
  • 如果需要释放常驻内存的对象,可以将变量重新赋值让旧的对象脱离引用关系:

    var arr = [1, 2, 3];
    console.log('hello');
    // 重新赋值
    arr = null; // 或 undefined
    

2、闭包

闭包中的私有变量不会被释放。

了解更多闭包相关知识,可参考:【JavaScript编程】闭包


3、定时器

setIntervalsetTimeout 设置之后如果没有清除,定时器的回调函数以及内部依赖的变量都不能被回收,造成内存泄漏。需要手动 clear

clearTimeout()
clearInterval()

4、DOM泄露

三、检查内存占用


1、浏览器

Chrome 浏览器查看内存占用,按照以下步骤操作:

1)打开开发者工具,选择 Performance 面板;
2)在顶部勾选 Memory;
3)点击左上角的录制按钮;
4)在页面上进行各种操作,模拟用户的使用情况;
5)一段时间后,点击对话框的 stop 按钮,面板上就会显示这段时间的内存占用情况。

在这里插入图片描述

2、命令行

使用 node 提供的 process.memoryUsage() 方法:

$ node
> process.memoryUsage()
{ rss: 21782528,
  heapTotal: 7684096,
  heapUsed: 4947864,
  external: 16837 }

rss(resident set size):所有内存占用,包括指令区和堆栈。
heapTotal:"堆"占用的内存,包括用到的和没用到的。
heapUsed:用到的堆的部分。(使用中的内存量)
external: V8 引擎内部的 C++ 对象占用的内存。

实例: 封装一个显示内存占用的方法,如下:

var showMem = function() {
    var mem = process.memoryUsage()
    var bf = function(bytes) {
        return (bytes / 1024 / 1024).toFixed(2) + 'MB'
    }
    console.log('Process: heapTotal:' + bf(mem.heapTotal) + ',heapUsed:' + bf(mem.heapUsed) + ',rss:' + bf(mem.rss))
    console.log('-------------------------------------------------------------')
}

然后写一个不停分配内存但不释放内存的代码:

var useMem = function() {
    var size = 20 * 1024 * 1024
    var arr = new Array(size)
    for (var i = 0; i < size; i++) {
        arr[i] = 0
    }
    return arr
}
var total = []
for (var j = 0; j < 15; j++) {
    showMem()
    total.push(useMem())
}
showMem()

执行可以看到,每次调用useMem都导致了3个值得增长,最后内存溢出。如下:

SG-MAC:$ node index.js
Process: heapTotal:6.83MB,heapUsed:4.21MB,rss:20.16MB
-------------------------------------------------------------
Process: heapTotal:166.84MB,heapUsed:164.25MB,rss:181.57MB
-------------------------------------------------------------
Process: heapTotal:326.85MB,heapUsed:324.26MB,rss:341.63MB
-------------------------------------------------------------
Process: heapTotal:486.86MB,heapUsed:484.26MB,rss:501.69MB
-------------------------------------------------------------
Process: heapTotal:646.88MB,heapUsed:644.26MB,rss:661.74MB
-------------------------------------------------------------
Process: heapTotal:806.89MB,heapUsed:804.26MB,rss:821.77MB
-------------------------------------------------------------
Process: heapTotal:966.90MB,heapUsed:964.27MB,rss:981.78MB
-------------------------------------------------------------
Process: heapTotal:1126.91MB,heapUsed:1124.27MB,rss:1141.80MB
-------------------------------------------------------------
Process: heapTotal:1286.92MB,heapUsed:1284.27MB,rss:1301.82MB
-------------------------------------------------------------

<--- Last few GCs --->

[45451:0x103000000]     1382 ms: Mark-sweep 1284.0 (1290.9) -> 1283.9 (1290.9) MB, 136.8 / 0.0 ms  allocation failure GC in old space requested
[45451:0x103000000]     1501 ms: Mark-sweep 1283.9 (1290.9) -> 1283.9 (1287.9) MB, 119.9 / 0.0 ms  last resort GC in old space requested
[45451:0x103000000]     1625 ms: Mark-sweep 1283.9 (1287.9) -> 1283.9 (1287.9) MB, 124.1 / 0.0 ms  last resort GC in old space requested

相关文档


vue 如何避免内存泄漏

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值