Node中GC机制以及如何防止内存泄露

  • 在js本身的gc机制,可以自动释放内存,但是无论是通过计数引用法,或者是标记清零法,都不能完全的避免内存泄露,前端js内存泄露,可以通过刷新浏览器来人为避免,但是nodejs在服务器端的内存泄露呢,定时重启服务器是一种方法,但是更好的是尽量的去避免内存泄露

    • 本文先分析了gc机制,以及内存泄露的原因,最后总结了避免内存泄露的方法

1.javascript的内存回收机制(gc机制)

(1)计数引用法

语言引擎有一张”引用表”,保存了内存里面所有的资源(通常是各种值)的引用次数。如果一个值的引用次数是0,就表示这个值不再用到了,因此可以将这块内存释放。

来举一个计数引用的例子:

  const name="yuxl";
  name="jonyyu"

分析一下,这里第一句我们将name赋值为“yuxl”,此时,“yuxl”的计数加1从0——>1,这样“yuxl”就存在了内存里面,第二句又将name赋值为“jonyyu”,此时“yuxl”的计数减1,从1变为了0,“jonyyu”的计数从0变为1,此时因为“yuxl”的计数为0,所以“yuxl”就从内存中被释放。

(2)标记清除法

  • 当变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”
  • 垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中变量所引用的变量(闭包),在这些完成之后仍存在标记的就是要删除的变量了
  var a="aa";
  function test(){
    var b="bb";
    console.log(a)
    console.log(b);
  }
  test();//输出“aa”,“bb”
  console.log(b)//输出“undefined”

我们来分析这个函数,调用test()的时候,进入test的执行环境,此时环境中存在了变量b,因为test函数的上下文中可以访问到全局变量a(根据函数的作用域原理),因此输出了“aa”,“bb”,当执行完这个函数以后,变量b标记被清除,也就是b被释放,因此在此后的console.log的语句中,b为undefined。

(3)计数引用法带来的内存泄露问题

计数引用法可能带来内存泄露,因此在js的gc机制中没有大量采用,比如:

  function test(){
    var a={};
    var b={};
    a.prop=b;
    b.prop=a;
  }
  test()

从上面的例子中,如果a,b中的属性相互引用,那么在函数运行后,如果采用计数引用法,它们之间的计数都为1,因此不会被清除。

2.通过WeakMap和WeakSet来解决计数引用法带来的内存泄露问题

虽然较少的浏览器采用了计数引用法来实现Js的gc机制,下面我们来看一下如何在计数引用法的情况下避免内存泄露的问题。
其原理就是:
对于某些情况下的引用,可以不计数,不计入引用次数。
具体实现方式:WeakMap,WeakSet,他们对于值的计数都不会计入垃圾回收机制。举例来说:

  const wm=new WeakMap();
  const element=document.getElementById('test');
  wm.set(element,'some message');
  wm.get(element);//可以得到值为“some message”

这是一个简单的例子,如果来看,此时:

  element=null

这样,令element为空,此时如果通过process.memoryUsage()来观察会发现内存已经被清空了。

3.内存泄露的几种原因

(1)全局变量

    a = 10;
    //未声明对象。

    global.b = 11;
    //全局变量引用

(2)闭包

  function test(){
    var x=10;
    return function test_child(){
       console.log(x)
    }
  }

调用test()后,x变量没有被释放。

(3)事件监听
Node.js 的事件监听也可能出现的内存泄漏。例如对同一个事件重复监听,忘记移除(removeListener),将造成内存泄漏。

(4)其他原因

有一些其他的情况可能会导致内存泄漏,比如缓存。在使用缓存的时候,得清楚缓存的对象的多少,如果缓存对象非常多,得做限制最大缓存数量处理。还有就是非常占用 CPU 的代码也会导致内存泄漏,服务器在运行的时候,如果有高 CPU 的同步代码,因为Node.js 是单线程的,所以不能处理处理请求,请求堆积导致内存占用过高。

4.如何避免内存泄漏

  • ESLint 检测代码检查非期望的全局变量。
  • 使用闭包的时候,得知道闭包了什么对象,还有引用闭包的对象何时清除闭包。最好可以避免写出复杂的闭包,因为复杂的闭包引起的内存泄漏
  • 绑定事件的时候,一定得在恰当的时候清除事件。在编写一个类的时候,推荐使用 init 函数对类的事件监听进行绑定和资源申请,然后 destroy 函数对事件和占用资源进行释放
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Node.js ,可以使用一些工具和技术来检测内存泄漏。下面是一些常用的方法: 1. 基于内存使用情况的监控工具:Node.js 提供了内置的 `process.memoryUsage()` 方法,可以获取当前 Node.js 进程的内存使用情况。可以在程序定期调用该方法并记录下来,以便在后续分析检测是否存在内存泄漏。 2. 堆快照分析工具:可以使用 V8 引擎提供的堆快照工具来分析内存使用情况。例如,可以使用 Chrome 开发者工具的 Heap Snapshot 功能来获取堆快照,并通过查看对象引用关系和对象占用的内存等信息,找出潜在的内存泄漏问题。 3. 内存泄漏检测工具:有一些第三方工具可用于在 Node.js 应用程序检测内存泄漏。例如,`heapdump` 和 `memwatch-next` 是常用的内存泄漏检测工具,它们可以帮助你捕获和分析内存泄漏问题。 4. 监控和分析工具:使用监控和分析工具可以实时监控应用程序的内存使用情况,并生成相应的报告。例如,`pm2` 是一个流行的进程管理工具,它可以监控应用程序的内存使用情况并生成报告。 在使用这些工具进行内存泄漏检测时,需要关注以下几个方面: - 内存增长情况:观察内存使用量是否逐渐增长,如果内存使用量持续增长但没有回收的迹象,可能存在内存泄漏。 - 对象引用关系:检查对象之间的引用关系,查看是否存在循环引用导致无法回收的情况。 - 定期检测:在应用程序运行期间定期进行内存检测,以便及早发现和解决潜在的问题。 通过以上方法和工具的结合使用,可以帮助你检测和解决 Node.js 应用程序的内存泄漏问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值