如何排查Node.js中未移除事件监听导致的内存泄漏?
- 内容介绍
- 文章标签
- 相关推荐

由于内存泄漏在Node.js中非常的常见,可能在浏览器中应用javascript时,对于其内存泄漏不是特别敏感,但作为服务器语言运行时,你就不得不去考虑这些问题。由于很小的逻辑可能导致服务器运行一天或者一个星期甚至一个月才会让你发现内存不断上涨,而终于会到那天你不得不重启服务来保护服务器的性能,那么这种问题就有必要在上线前进行一个系统检测,一边在上线后能够有一个有效的监控程序来保证运行平安。 我真的搞不懂为什么大家对这个事情不重视,难道等着服务器崩了才后悔吗?唉,真是让人头疼,对吧,你看。。
什么是内存泄漏
太顶了。 内存泄漏也称作 存储渗漏 ,用动态存储分配函数分配的内存空间在使用完毕后没有及时释放, 这部分内存就无法被程序 使用,从而造成资源浪费。如果长期发生,会导致系统性能下降甚至崩溃。想想都可怕!
Node.js 事件监听与内存泄漏
你没事吧? Node.js 的事件监听也可能出现的内存泄漏。比方说对同一个事件重复监听,忘记移除,将造成内存泄漏。这种情况很容易在复用对象上添加事件时出现,所以事件重复监听可能收到如下警告: Warning: Possible EventEmitter memory leak detected。11 haha listeners added。
Use emitter。setMaxListeners to increase limit 比方说,Node.js 中 Agent 的 keepAlive 为 true 时,可能造成的内存泄漏。当 Agent keepAlive 为 true 的时候,将会复用之前使用过的 socket,如果在 socket 上添加事件监听,忘记清除的话,主要原因是 socket 的复用,将导致事件重复监听从而产生内存泄漏,好吧好吧...。
常见的 Node.js 框架对比
| 框架 | 特点 | 适用场景 | 学习曲线 |
|---|---|---|---|
| Express | 轻量级、 灵活 | API 服务器、小型应用 | 简单 |
| NestJS | TypeScript、模块化、可 | 大型企业级应用 | 陡峭 |
| Koa | 异步编程、中间件机制 | 高并发场景 | 中等 |
| Hapi | 配置驱动、平安性高 | 企业级应用、API 服务器 | 复杂 |
泄漏类型
| 类型 | 典型表现 | 检测工具重点观察区域 |
|---|---|---|
| 闭包累积 | 内存随请求量线性增长 | Closure对象数量异常 |
| 缓存失控 | 缓存大小监控超出预期 | Array/Map对象体积过大 |
| 事件监听未移除 | EventEmitter监听器数量激增 | listener计数异常 |
更详细的描述
闭包的滥用绝对是噩梦!有时候你以为只是一个小小的作用域,后来啊它却把整个对象树都抱住了永远无法被回收…真是哭笑不得啊!缓存失控更可怕了无限增长的缓存直接把服务器逼到绝境! 要我说... 还有那些忘记移除的事件监听器…简直就是定时炸弹!它们会在后台默默地积累,直到有一天彻底爆发!我发誓一定要写好单元测试防止这些问题的发生!
3. 深度剖析:一个真实案例的完整排查过程
去年我们处理过一个棘手的案例:一个日均百万PV的API服务,每天固定泄漏300MB内存。的排查流水账:
- 现象确认: 对比快照: // 在流量低谷和高峰分别
Heap Profiling 使用方法
- 打开 Chrome DevTools
- 选择 "Memory" tab
- 点击 "Take heap snapshot"
- 选择 "Comparison" view 并加载两个快照进行对比
记一次 Node.js 内存泄漏排查 文章浏览阅读254次。本文分享了一次Node.js记忆泄露排查的经历, 作者通过使用工具分析记忆快照,并在社区帮助下到头来定位了问题根源——错误地重复聆听时间。进来就知道这是朴灵大大Node.js团队群了 ONS的问题直接就没有问了这个群也就淹没在大堆消息里了。昨天突然想起我的记忆泄露问题正是这个群覆盖范围内的范畴,赶紧在群里反应我的问题得到了@奕钧及时响应先根据我的截图猜测到是时间重复聆听后又加入我的项目帮忙查看记忆快... Google Chrome Heap Profiling GoogleChrome浏览器提供了非常强大的JS调试工具Heap Profiling便是其中一个。Heap Profiling可以记录当前的堆记忆快照并生成对象的描述文件该描述文件给出了当时JS运行所用到的所有对象以及这些对象所占用的记忆大小引用的层级关系等等这些描述文件为记忆泄露的排查提供了非常有用的信息。 注意:本文里的所有例子均基于Google Chrome浏览器。 什么是heap JS运行的时候会有栈记忆和堆记忆当我们用new实例化一个类的时候这个new出来的对象就保存在heap里面而这个对象的引用则存储在stack里程序通过stack里的引用找到这个对象...,公正地讲...
挺好。 解决办法 - removeListener的重要性 注意它更改侦听器后面的侦听器数组中的数组索引removeListener将最多删除侦听器数组中的一个侦听器实比方说果任何单个侦听器已多次添加到指定时间的侦听器数组中则必须多次调用removeListener才能删除每个实例返回触发器所以呢可以链接调用 删除所有侦听器或指定时间的侦听器返回发射器所以呢可以链接调用默认情况下一个特定的时间最多添加10个侦听器如果为特定时间添加了10多个侦听器则EventEmitter将显示警告这是一个有用的默认值它有助于查找记忆泄露明摆着不是所有的发射器都应该限制为10个这个功能允许增加设为零为无限 返回指...
EventEmitter核心功能
Node.js所有的异步 I/O 操作在完成时都会发送一个时间到时间队列。 Node.js里面的许多对象都会分发时间:一个netServer对象会在每次有新连接时分发一个时间 一个fsreadStream对象会在文件被打开的时候发出一个时间 所有这些产生时间的都是 eventsEventEmitter 的实例。 events模块只提供了一个对象eventsEventEmitter EventEmitter的核心就是时间触发与时间聆听器的功能的封装。 EventEmitter 的每个时间由一个时间和若干个参数组成时间和是一个字符串通常表达一定的语义对于每个时间EventEmitter 支持若干个事件聆听器当时间触发时注册到这个事件...
由于内存泄漏在Node.js中非常的常见,可能在浏览器中应用javascript时,对于其内存泄漏不是特别敏感,但作为服务器语言运行时,你就不得不去考虑这些问题。由于很小的逻辑可能导致服务器运行一天或者一个星期甚至一个月才会让你发现内存不断上涨,而终于会到那天你不得不重启服务来保护服务器的性能,那么这种问题就有必要在上线前进行一个系统检测,一边在上线后能够有一个有效的监控程序来保证运行平安。 我真的搞不懂为什么大家对这个事情不重视,难道等着服务器崩了才后悔吗?唉,真是让人头疼,对吧,你看。。
什么是内存泄漏
太顶了。 内存泄漏也称作 存储渗漏 ,用动态存储分配函数分配的内存空间在使用完毕后没有及时释放, 这部分内存就无法被程序 使用,从而造成资源浪费。如果长期发生,会导致系统性能下降甚至崩溃。想想都可怕!
Node.js 事件监听与内存泄漏
你没事吧? Node.js 的事件监听也可能出现的内存泄漏。比方说对同一个事件重复监听,忘记移除,将造成内存泄漏。这种情况很容易在复用对象上添加事件时出现,所以事件重复监听可能收到如下警告: Warning: Possible EventEmitter memory leak detected。11 haha listeners added。
Use emitter。setMaxListeners to increase limit 比方说,Node.js 中 Agent 的 keepAlive 为 true 时,可能造成的内存泄漏。当 Agent keepAlive 为 true 的时候,将会复用之前使用过的 socket,如果在 socket 上添加事件监听,忘记清除的话,主要原因是 socket 的复用,将导致事件重复监听从而产生内存泄漏,好吧好吧...。
常见的 Node.js 框架对比
| 框架 | 特点 | 适用场景 | 学习曲线 |
|---|---|---|---|
| Express | 轻量级、 灵活 | API 服务器、小型应用 | 简单 |
| NestJS | TypeScript、模块化、可 | 大型企业级应用 | 陡峭 |
| Koa | 异步编程、中间件机制 | 高并发场景 | 中等 |
| Hapi | 配置驱动、平安性高 | 企业级应用、API 服务器 | 复杂 |
泄漏类型
| 类型 | 典型表现 | 检测工具重点观察区域 |
|---|---|---|
| 闭包累积 | 内存随请求量线性增长 | Closure对象数量异常 |
| 缓存失控 | 缓存大小监控超出预期 | Array/Map对象体积过大 |
| 事件监听未移除 | EventEmitter监听器数量激增 | listener计数异常 |
更详细的描述
闭包的滥用绝对是噩梦!有时候你以为只是一个小小的作用域,后来啊它却把整个对象树都抱住了永远无法被回收…真是哭笑不得啊!缓存失控更可怕了无限增长的缓存直接把服务器逼到绝境! 要我说... 还有那些忘记移除的事件监听器…简直就是定时炸弹!它们会在后台默默地积累,直到有一天彻底爆发!我发誓一定要写好单元测试防止这些问题的发生!
3. 深度剖析:一个真实案例的完整排查过程
去年我们处理过一个棘手的案例:一个日均百万PV的API服务,每天固定泄漏300MB内存。的排查流水账:
- 现象确认: 对比快照: // 在流量低谷和高峰分别
Heap Profiling 使用方法
- 打开 Chrome DevTools
- 选择 "Memory" tab
- 点击 "Take heap snapshot"
- 选择 "Comparison" view 并加载两个快照进行对比
记一次 Node.js 内存泄漏排查 文章浏览阅读254次。本文分享了一次Node.js记忆泄露排查的经历, 作者通过使用工具分析记忆快照,并在社区帮助下到头来定位了问题根源——错误地重复聆听时间。进来就知道这是朴灵大大Node.js团队群了 ONS的问题直接就没有问了这个群也就淹没在大堆消息里了。昨天突然想起我的记忆泄露问题正是这个群覆盖范围内的范畴,赶紧在群里反应我的问题得到了@奕钧及时响应先根据我的截图猜测到是时间重复聆听后又加入我的项目帮忙查看记忆快... Google Chrome Heap Profiling GoogleChrome浏览器提供了非常强大的JS调试工具Heap Profiling便是其中一个。Heap Profiling可以记录当前的堆记忆快照并生成对象的描述文件该描述文件给出了当时JS运行所用到的所有对象以及这些对象所占用的记忆大小引用的层级关系等等这些描述文件为记忆泄露的排查提供了非常有用的信息。 注意:本文里的所有例子均基于Google Chrome浏览器。 什么是heap JS运行的时候会有栈记忆和堆记忆当我们用new实例化一个类的时候这个new出来的对象就保存在heap里面而这个对象的引用则存储在stack里程序通过stack里的引用找到这个对象...,公正地讲...
挺好。 解决办法 - removeListener的重要性 注意它更改侦听器后面的侦听器数组中的数组索引removeListener将最多删除侦听器数组中的一个侦听器实比方说果任何单个侦听器已多次添加到指定时间的侦听器数组中则必须多次调用removeListener才能删除每个实例返回触发器所以呢可以链接调用 删除所有侦听器或指定时间的侦听器返回发射器所以呢可以链接调用默认情况下一个特定的时间最多添加10个侦听器如果为特定时间添加了10多个侦听器则EventEmitter将显示警告这是一个有用的默认值它有助于查找记忆泄露明摆着不是所有的发射器都应该限制为10个这个功能允许增加设为零为无限 返回指...

