-
Notifications
You must be signed in to change notification settings - Fork 89
Description
Hi, All
I found that mixing object_t to create objects in asio connection may cause a serious memory leak.
- How to reproduce my problem?
Add the following function to asio-example.cpp. I reuse the Calculator class.
void creat_calculator(boost::asio::io_context& io, std::shared_ptr<sdbusplus::asio::connection>& conn)
{
static long suffix = 0;
static boost::asio::steady_timer timer(io);
if (std::filesystem::exists("./creat_flag"))
{
boost::asio::post(io, [&](){creat_calculator(io, conn);});
if (suffix++ % 1000 == 0)
{
std::cout << "suffix = " << suffix << std::endl;
}
// Create a calculator object at /net/poettering/calculator
Calculator c1{*conn, std::string{"/net/poettering/calculator"}.append(std::to_string(suffix)).c_str()};
}
else
{
timer.expires_after(std::chrono::seconds(5));
timer.async_wait([&](const boost::system::error_code& ){
// malloc_stats();
creat_calculator(io, conn);
});
}
}
If I use connection to create a dbus object and start running it using io.run(). If I start a new io task and use object_t to create objects at a very high frequency, I can soon observe an abnormal increase in Rss in the process's /proc/$PID/smaps. Next, I stop using object_t to create objects, and Rss does not return to normal levels quickly, but remains at a relatively high abnormal level. Then, I send a method_call to this process, such as Ping(), and I will receive a response after a long time.
At the same time, if I use busctl monitor to detect the InterfaceAdded signal issued when creating an object_t object, I will observe that before sending a method_call to the process, I cannot monitor the expected InterfaceAdded signal, but after sending Ping(), I monitor the InterfaceAdded signals that should have been issued when creating the object_t object.
- Possible reasons I found.
In the read_wait of connection, we originally wanted to monitor POLLIN, POLLOUT and timeout. If the bus is idle for long enough, get_events() can only return POLLIN, so we only monitor the EPOLLIN event of bus input_fd, and there will be no timeout. This means that we only execute process() when there is an incoming message.
Unfortunately, the InterfaceAdded sent by object_t is only an outgoing message, and it does not expect a method_return like async_method_call. At the same time, I found in the source code of sd-bus that sd_bus_send will cache outgoing messages to wqueue when there are too many messages, and sd_bus_process is required to continue to send these outgoing messages. This means that if there is no incoming message, these messages in the wqueue queue will not be sent, and at most 384*1024 messages will be accumulated in the wqueue queue and cannot be released; at the same time, if any incoming message is received, process() will start to execute, and then the messages in the wqueue queue will be properly processed.
I think we may need a timer to periodically check whether there is data to be processed in rqueue and wqueue. Considering that adding a timer may affect the performance of the program, I am not sure whether this timer should be added. I would like to seek your opinions.