@
clowwindy 反复malloc/free不是问题所在,因为malloc和free的速度相当快。
真正的问题在libuv上,因为libuv在远端有数据时会不停的申请内存读取,而写到客户端的速度相对较慢,导致writing queue里大量请求堆积。而在写入操作完成后,libuv不会立即调用callback,而是将callback append到了一个叫做write_completed_queue 的 queue里等待机会调用,参考:
https://github.com/joyent/libuv/blob/master/src/unix/stream.c#L678-L683而根据libuv的工作原理,write callback负责free申请的buffer,如果callback得不到机会调用,buffer就无法被真正的释放。
uv__write_callbacks,这个函数会empty queue并且call每个callback:
https://github.com/joyent/libuv/blob/master/src/unix/stream.c#L846-L858问题是这个函数只有在EPOLL POLLOUT的时候才会被call,而在libuv疯狂接收YouTube视频的时候,POLLOUT的机会是很少的。
shadowsocks-libuv最早的时候有跟你描述的一模一样的问题,后来发现是请求堆积后在内部维护了一个计数器,限制writing queue的长度,这也就是config.h中的MAX_PENDING_PER_CONN的作用,否则以美帝的网速,内存很快就被申请爆了。