Fix memory leak in Transform Listener#630
Conversation
So we do actually need to react to parameter events in TimeSource. The reason is so that we can do the right thing when the user enables or disables simulation time via the However, we don't exactly need to subscribe to it anymore. Since Iron, we have the ability to get a callback after a parameter has been updated, using the So my suggestion is that instead we open a PR to We can also consider taking this PR, for the reasons you describe, but I think that is a separate issue. @zygfrydw are you willing to open that PR to |
|
I am not exactly sure what it changes to replace the In the I do not understand why both In my opinion, it is not correct to spin only the We are currently locked on the ROS Humble version so we hope you merge this pull request to ROS Humble as well. |
|
Hello, Here is a graph of time vs. memory usage of every node in our system, gathered over 548 minutes (9.1 hours) of robot idle time. The lines with an incline are nodes with From eyeballing these results, it looks to me like every Just wanted to put here some experimental support for your diagnosis. Not sure if the fix here helps us yet, but we are very suspicious that this object is the one that is leaky, and we will report back. |
|
I also created a small repository to run experiments. I spawn a dummy node that doesn't do anything, just advertise a parameter which I later use to send a big string payload. After putting the payload into the parameter, I started seeing memory leaks. The confusing part is that with/without Indeed if a LeakyNode - No tf stuffclass LeakyNode : public rclcpp::Node {
public:
explicit LeakyNode(const std::string &name) : Node(name) {
this->declare_parameter("my_parameter", "world");
}
};LeakyNode - with dummy TransformListenerclass LeakyNode : public rclcpp::Node {
public:
explicit LeakyNode(const std::string &name) : Node(name) {
this->declare_parameter("my_parameter", "world");
tf_buffer = std::make_unique<tf2_ros::Buffer>(this->get_clock());
tf_listener = std::make_unique<tf2_ros::TransformListener>(*tf_buffer);
}
std::unique_ptr<tf2_ros::TransformListener> tf_listener;
std::unique_ptr<tf2_ros::Buffer> tf_buffer;
};ConclusionsI don't have anyone yet 😢 So far all the experiments I have done are in some way contradictory (common in memory leak hunting). Any leads on how to nail down this problem would be highly appreciated |
|
@zygfrydw Was this issue fixed with the @nachovizzo PR #636 ? Feel free to reopen it again, if the problem is still there |
|
I've just tested current ros2:humble Also tested for other ros2 distributions:
@clalancette @zygfrydw @ahcorde I'm kindly asking to reopen this issue. |
This is an old issue that we think we've solved a long time ago. Please open a new issue with your findings and how to reproduce. |
|
With all respect, it doesn't make sense to open a new issue, since it wasn't fixed and will contain the same content as this one. I've only reproduced the steps which @zygfrydw mentioned. |



There is a memory / message leak when using
TransformListenerconstructed with internal node.When
TransformListeneris constructed in the following way:There is a memory leake due to messages published to
/parameter_eventswhich is not served in the internal node.We have observed it when using CycloneDDS with shared memory (Iceoryx) and we have created a repo to reproduce this error.
The reason for this issue is that, when in
TransformListeneris created dedicated thread, the subcriptions for/tfand/tf_statictopic are added to callback group. When internal node is created, the node creates subcription on topic/parameter_events. However this subscription is created in default callback group which is never spinned by the executor (the executor is told explicitly to run only the callback group with/tfand/tf_static).The topic
/parameter_eventsis created with QOS with history of 1000 messages. Therefore not served messages live forever in/parameter_eventsfor eachTransformListener.In the application with default CycloneDDS this results in small, constant memory leak in each instance of
TransformListener, however when messages are taken from pool like when using Shared Memory, the memory pool is exausted quickly.The
/parameter_eventsis created inrclcpp::TimeSource::NodeStateinrclcpp/src/rclcpp/time_source.cpp:270.In my opinion this subcription on parameter events is not necessary in this internal node, however I do not see any option to disable this. Additionaly, the problem will come back if someone adds other subscriptions in Node in future, hance I perfer current solution with adding default callback group to executor.
Other possible solution is: