ros2 / rmw_cyclonedds

ROS 2 RMW layer for Eclipse Cyclone DDS
Apache License 2.0
112 stars 91 forks source link

Memory leak when using ROS 2 actions #388

Open alsora opened 2 years ago

alsora commented 2 years ago

Bug report

Invoking ROS 2 actions causes a small memory leak with CycloneDDS. This has been experienced on the Create 3 robot, where the robot crashed after few hours of continuously commanding actions.

It's easy to reproduce the problem on x86_64. The memory leak seems to be specific to cyclonedds, as it does not happen with fast-dds.

Required Info:

Steps to reproduce issue

Create a ROS 2 node with an action server that rejects every goal request (this is not necessary, but it simplifies the scenario).

#include <functional>
#include <memory>
#include "example_interfaces/action/fibonacci.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"

class MinimalActionServer : public rclcpp::Node
{
public:
  using Fibonacci = example_interfaces::action::Fibonacci;
  using GoalHandleFibonacci = rclcpp_action::ServerGoalHandle<Fibonacci>;

  explicit MinimalActionServer(const rclcpp::NodeOptions & options = rclcpp::NodeOptions())
  : Node("minimal_action_server", options)
  {
    using namespace std::placeholders;

    this->action_server_ = rclcpp_action::create_server<Fibonacci>(
      this->get_node_base_interface(),
      this->get_node_clock_interface(),
      this->get_node_logging_interface(),
      this->get_node_waitables_interface(),
      "fibonacci",
      std::bind(&MinimalActionServer::handle_goal, this, _1, _2),
      std::bind(&MinimalActionServer::handle_cancel, this, _1),
      std::bind(&MinimalActionServer::handle_accepted, this, _1));
  }

private:
  rclcpp_action::Server<Fibonacci>::SharedPtr action_server_;

  rclcpp_action::GoalResponse handle_goal(
    const rclcpp_action::GoalUUID & uuid,
    std::shared_ptr<const Fibonacci::Goal> goal)
  {
    (void)uuid;
    (void)goal;
    return rclcpp_action::GoalResponse::REJECT;
  }

  rclcpp_action::CancelResponse handle_cancel(
    const std::shared_ptr<GoalHandleFibonacci> goal_handle)
  {
    (void)goal_handle;
    return rclcpp_action::CancelResponse::ACCEPT;
  }

  void handle_accepted(const std::shared_ptr<GoalHandleFibonacci> goal_handle)
  {
    (void)goal_handle;
  }
};

int main(int argc, char ** argv)
{
  rclcpp::init(argc, argv);
  auto action_server = std::make_shared<MinimalActionServer>();
  rclcpp::spin(action_server);
  rclcpp::shutdown();
  return 0;
}

Then use a bash script to send action requests forever (like this)

while true
do
  date; ros2 action send_goal /fibonacci example_interfaces/action/Fibonacci "{}"
  cat /proc/$(pidof action_server_member_functions)/status | grep -e "Vm....:"
done 

Expected behavior

The virtual memory does not change.

Actual behavior

The virtual memory increases constantly with every action request.

clalancette commented 2 years ago

In good news, I tested this scenario out with both Fast-DDS and CycloneDDS in Rolling, and I don't see the leak. So there is a fix that went in sometime since Galactic that fixes this. The trick is tracking down that patch.

KavenYau commented 2 years ago

I met a similar situation on Foxy, but I am not sure because I haven't delved into it yet. Hoping the patch can be tracked out.

eboasson commented 2 years ago

My guess: https://github.com/eclipse-cyclonedds/cyclonedds/issues/1146 (original issue) and https://github.com/ros2/rmw_cyclonedds/pull/373 (fix)

shamlian commented 2 years ago

Unfortunately, this #373 doesn't seem to be the root cause, from my testing.