Skip to content

Conversation

@Barry-Xu-2018
Copy link
Contributor

@Barry-Xu-2018 Barry-Xu-2018 commented Oct 18, 2024

Address a bug while investigating #1371

If write action client code like below,

            while rclpy.ok:
                future = action_client.send_goal(xxx)
                rclpy.spin_until_future_complete(action_client, future)

In spin_until_future_complete(), a callback is added to the done callback of future. And next spin_once_until_future_complete() will be called continuously.

def spin_until_future_complete(
self,
future: Future,
timeout_sec: Optional[float] = None
) -> None:
"""Execute callbacks until a given future is done or a timeout occurs."""
# Make sure the future wakes this executor when it is done
future.add_done_callback(lambda x: self.wake())
if timeout_sec is None or timeout_sec < 0:
while self._context.ok() and not future.done() and not self._is_shutdown:
self.spin_once_until_future_complete(future, timeout_sec)
else:
start = time.monotonic()
end = start + timeout_sec
timeout_left = TimeoutObject(timeout_sec)
while self._context.ok() and not future.done() and not self._is_shutdown:
self.spin_once_until_future_complete(future, timeout_left)

Each time spin_once_until_future_complete() is called, the same callback is added to the future's done callback.

def spin_once_until_future_complete(
self,
future: Future,
timeout_sec: Optional[Union[float, TimeoutObject]] = None
) -> None:
future.add_done_callback(lambda x: self.wake())
self._spin_once_impl(timeout_sec, future.done)

This way, the future's done callbacks keep accumulating.

When a future is completed (calls set_result()), _schedule_or_invoke_done_callbacks() is called.
In this function, it creates a Task for each done callback, which leads to many unnecessary Tasks being created and consuming more and more memory.

rclpy/rclpy/rclpy/task.py

Lines 150 to 153 in a09a031

if executor is not None:
# Have the executor take care of the callbacks
for callback in callbacks:
executor.create_task(callback, self)

So this PR is to remove the code that adds unnecessary done callbacks.

Copy link
Collaborator

@fujitatomoya fujitatomoya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm with green CI.

@Barry-Xu-2018 btw could you check if this PR fixes the memory leak issue #1371

@fujitatomoya fujitatomoya self-assigned this Oct 18, 2024
@fujitatomoya fujitatomoya added the bug Something isn't working label Oct 18, 2024
@Barry-Xu-2018 Barry-Xu-2018 changed the title Fix a bug on unfinished task increasing while repeatedly calling spin_until_future_complete Fix a bug on adding unnecessary done callback of future while repeatedly calling spin_until_future_complete Oct 19, 2024
@Barry-Xu-2018
Copy link
Contributor Author

@fujitatomoya

In my environment, the action client memory still increases a bit, but it's much less than before.

@Barry-Xu-2018 Barry-Xu-2018 force-pushed the review/topic-fix-unfinished-task-increase branch from 5193156 to d495a94 Compare October 19, 2024 07:53
@Barry-Xu-2018
Copy link
Contributor Author

Only update commit description in d495a94

@Barry-Xu-2018
Copy link
Contributor Author

CI:

  • Linux Build Status
  • Linux-aarch64 Build Status
  • Linux-rhel Build Status
  • Windows Build Status

@fujitatomoya
Copy link
Collaborator

@clalancette @sloretz @ahcorde could either of you review this?

@ahcorde ahcorde merged commit c009b0d into ros2:rolling Oct 25, 2024
3 checks passed
alneremin pushed a commit to alneremin/rclpy that referenced this pull request Dec 17, 2024
@bmartin427
Copy link
Contributor

Can this be backported? I just tripped over it in Jazzy.

@fujitatomoya
Copy link
Collaborator

@Mergifyio backport jazzy

@mergify
Copy link
Contributor

mergify bot commented Oct 22, 2025

backport jazzy

✅ Backports have been created

mergify bot pushed a commit that referenced this pull request Oct 22, 2025
… spin_until_future_complete (#1374)

Signed-off-by: Barry Xu <[email protected]>
(cherry picked from commit c009b0d)

# Conflicts:
#	rclpy/rclpy/executors.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants