qicosmos / rest_rpc

modern C++(C++11), simple, easy to use rpc framework
MIT License
1.66k stars 365 forks source link

调用rpc_server的publish函数出现内存泄漏 #21

Open LeoYang-Chuese opened 3 years ago

LeoYang-Chuese commented 3 years ago

问题描述

调用rpc_server的publish函数出现内存泄漏,参数为自定义结构体集合,如vector<PclPoint>,size()=200000,详见Demo源码

开发环境

Demo操作描述

Demo分为数据发布端Server和数据订阅端Client,分别部署在不同的电脑上。Server启动后即以每秒发布长度为200000的vector数据和长度为20000的vector数据。Client端启动后输入Server端的IP地址,选择订阅的数据类型,开始接收数据。

image-20201016213024927

内存泄漏检测结果

使用Deleaker工具检测结果如图1所示。

image-20201016204514854

​ 图1 Deleaker工具内存泄漏检测结果

使用 Inter Inspector工具检测结果如图2、图3和图4所示。

image-20201016210202990

​ 图2 Inter Inspector工具内存泄漏检测结果1

image-20201016210326048

​ 图3 Inter Inspector工具内存泄漏检测结果2

image-20201016211011385

​ 图4 Inter Inspector工具内存泄漏检测结果3

@qicosmos 劳烦给看看,谢谢!

qicosmos commented 3 years ago

Hi,你观察到进程的内存在不断上涨吗?

LeoYang-Chuese commented 3 years ago

是的。内存达到几百M时就会抛出bad allocation异常。 以vector<PclPoint>举例,我还观察到一些现象:

感觉像发送队列出现积压,内存无法及时释放,导致内存泄露。

qicosmos commented 3 years ago

看起来是发送队列堆积了太多数据没有发送出去,可以定时打印一下发送队列size,然后观察一下size是不是持续增长。 如果size持续增长那就说明是内存堆积引起的。

LeoYang-Chuese commented 3 years ago

Debug看到write_queue_的size在不断增加,我试着打印出来。 请问RPC数据传输模式能否支持 2M/秒 的传输量?

qicosmos commented 3 years ago

这个2m每秒是指什么,rest_rpc可以跑满网卡的。

qicosmos commented 3 years ago

Debug看到write_queue_的size在不断增加,我试着打印出来。 请问RPC数据传输模式能否支持 2M/秒 的传输量?

如果size在不断增加则要看看是不是subscribe端处理得太慢了,而publish太快了,导致消息在服务端堆积。

LeoYang-Chuese commented 3 years ago

这个2m每秒是指什么,rest_rpc可以跑满网卡的。

我指的2MB/s。

vector<PclPoint>的size=100000,经过15分钟,write_queue_的size超过100。

如果是subscribe端处理得太慢,那在同一台电脑运行则不会(没那么容易)出现消息堆积的问题,这是什么原因呢? 谢谢指教!

qicosmos commented 3 years ago

这个2m每秒是指什么,rest_rpc可以跑满网卡的。

我指的2MB/s。

vector<PclPoint>的size=100000,经过15分钟,write_queue_的size超过100。

如果是subscribe端处理得太慢,那在同一台电脑运行则不会(没那么容易)出现消息堆积的问题,这是什么原因呢? 谢谢指教!

本机网络延迟低,你可以修改一下测试用例,subsribe的客户端收到消息后什么都不做,看看这样内存还会不会堆积。你可以定时把发送队列长度打出来。

LeoYang-Chuese commented 3 years ago

谢谢解答。 subscribe的客户端收到消息不做任何处理确实能减少publish的服务端的消息堆积。但在实际情况中无法保证客户端及时的处理消息,最终服务端还是无法避免出现消息堆积。是否考虑增加可选的防止消息队列堆积的机制,如:

丢弃消息也是可以接受的,毕竟当消息堆积太多时,会使得内存空间不可用,严重可能内存溢出,服务宕机。

qicosmos commented 3 years ago

两个解决方法:

  1. 加一个接口吧,可以获取server端堆积的消息数,由用户去决定当消息数到达一定数量的时候丢消息或者自己持久化之类的处理。 2.server加一个最大堆积消息数的参数设置,当到了上限的时候server自动丢弃消息。

个人倾向方法1更好,让用户去灵活处理,方法2是server丢消息,让用户没法自己处理了。

LeoYang-Chuese commented 3 years ago

两个解决方法:

  1. 加一个接口吧,可以获取server端堆积的消息数,由用户去决定当消息数到达一定数量的时候丢消息或者自己持久化之类的处理。 2.server加一个最大堆积消息数的参数设置,当到了上限的时候server自动丢弃消息。

个人倾向方法1更好,让用户去灵活处理,方法2是server丢消息,让用户没法自己处理了。

我觉得这两种方式都可以有,分别针对不同场景。 方法2对于我们现在的场景就有用,Server负责从不同设备仪器采集数据,当Client只需要显示状态信息时,堆积的消息丢弃不会有什么影响。 我添加了一个PR,暂时满足我们项目的需要,不一定要合并,希望考虑添加类似接口,谢谢。

qicosmos commented 3 years ago

👌