socket.io内存不释放的问题
发布于 9 年前 作者 rongwj 6736 次浏览 最后一次编辑是 8 年前 来自 问答

我利用socket.io库做一个视屏弹幕的后台服务 node开启了手动回收内存(–expose-gc)

在我利用脚本做压力测试事,模拟1000个客户端,所有客户端在一个for循环发1个消息。 此时服务端内存增加很快,在断开连接后,内存没有下降。

8 回复

调用gc()来手动回收; 另外可以分析下内存profiler,看看是哪写对象占用的内存最多,再看代码里这些对象有没有一直被引用着。

你之前是写C的? 每次看到这些个sockeio连接断开,内存不释放问题,我就想问下,你知道node的gc机制吗?你线上服务也能手动gc?既然让v8去做gc管理,就不要苛刻他的回收。建立socke连接本来就是一个耗内存的操作,你断开后连接后基于正常的惰性回收机制,不会立即回收,确切说是不可能立即回收,只有等到你再次到达那个阀值或者超过那个阀值,才会触发全面的gc,否则小gc不会有太大的内存波动。抛开这个问题不谈,问一个问题的时候,node的gc机制大概了解下也不会问出这样的问题;

@haozxuan 我去年刚毕业,是学C的 node的垃圾回收机制,我只是通过朴灵的《深入浅出NODEjs》有点了解 我利用定时器调用gc(),手动的回收内存。 我在建立1000个连接单不发送消息,断开连接后内存会回收 但是建立连接后发送消息后,内存会回收一部分,但不能全部回收

@rongwj 抱歉,早上可能语气有些冲;其实node的gc机制是“不可控”的,他并不像c或者其他语言,申请一个变量,完了就结束释放掉,如果仔细研究他的垃圾回收机制的话,你会发现,他主要使用分代式回收机制,新生代内存使用完毕后会立即释放,但是对于老生代内存由于存储的对象不适合大规模的回收,所以只有等到新生代对象晋升到老生代内存不够的情况下,才会触发回收老生代内存,举个栗子,假如新生代比老生代为2:4,此时新生代实际有2份,老生代里面已经存储了3份,假如有2份的新生代晋升到老生代时,发现2+3>4,溢出了老生代内存限制,这个时候才会触发老生代的gc,也就是所谓的惰性回收机制,你可以通过process.memoryUsage()看到,虽然RSS很大,但是实际used会很小;

垃圾回收机制本身就是解决了开发者手动回收内存的处理 降低开发者技术要求 所以放心交给gc就好了

gc这个问题,你可以试着不断进行连接来测试,就是,连接1000个,断开,再连接一千个,断开,这样不断循环,理论上就可以获得一个稳定的内存占用。。。如果不是的话,看看是不是用了全局变量数组来存放东西,另外测试时可以考虑用ulimit进行限制,缩短测试时间

另外,用定时器调用gc是错误的,会导致性能问题,因为你不能保证你调用的时间刚好不在处理请求,虽说gc只是建议回收内存,但是在一些情况下仍会造成线程被挂起一段时间,gc的用法应该在明确的知道马上会进行大量内存分配的时候(并且不想被中途打断),辅助v8选择合适的时机进行垃圾收集,其实一般情况下这个函数作用有限,滥用后果却比较负面,相比之下,v8自己的机制在大多数情况下还是比代码层面的优化好很多

来自酷炫的 CNodeMD

试着接入 alinode, 然后压测下,我们一起看看。

回到顶部