1

I'd been wondering if the local variables in an async method in .Net will be Garbage Collected when not in use anymore. This will be extremely important for long-running Tasks.

For example, take this method as an example:

async void IterateForAnIternity()
{
   int c = 0;
   SomeClass _class = new SomeClass();
   while(true)
   {
      int newVar = c * c;
      LogMessage log = new LogMessage($"new var is now {newVar}");
      log.Print();
      var _tmp = _class.ReturnSomeBigStruct();
      await return Task.Yield();
   }
}

(the syntax may be wrong, but you get the idea)

If there's any docs on this, I'd appreciate it if you linked. I couldn't find anything online.

vvvvv
  • 25,404
  • 19
  • 49
  • 81
Cool guy
  • 175
  • 2
  • 7
  • 4
    No they are not, unless the task itself is dumped without a continuation – Charlieface Aug 21 '22 at 09:42
  • 1
    Objects are not garbage-collected if they are reachable from any root. "Any root" includes all the threads in the application. – Matthew Watson Aug 21 '22 at 09:45
  • 2
    Somewhat related: [Can .NET Task instances go out of scope during run?](https://stackoverflow.com/questions/2782802/can-net-task-instances-go-out-of-scope-during-run) Also this: [Will an object containing a never-ending task ever be garbage collected?](https://stackoverflow.com/questions/38145621/will-an-object-containing-a-never-ending-task-ever-be-garbage-collected) – Theodor Zoulias Aug 21 '22 at 09:56
  • 1
    Each time around the while loop, the space occupied by those inner variables will be reused, so it's not like you will end up out of memory, if that's what you were thinking – Neil Aug 21 '22 at 10:16
  • 1
    On a high level: _async_ methods are being expanded by compiler as state machines and local variables are being captured as fields there. So, as long as state machine is there -> there is a reference to a local variable captured in a field, therefore it won't be GCed. – Monsieur Merso Aug 21 '22 at 10:41
  • @Neil yes that was what I was thinking... it's interesting that .Net reuses the memory . but is there any docs related to this? I'm amazed why there wasn't anything online that I could find... thanks again! – Cool guy Aug 23 '22 at 07:26
  • 1
    `async void` is for event handlers and should not be used otherwise. – Jodrell Aug 24 '22 at 10:19
  • @Jodrell it's time handling makes it overwhelmingly easy to use it for long term jobs. specially when we want to play animation sequences inside it! (for games). why would you say it's not suited for that? – Cool guy Aug 24 '22 at 12:32
  • @Coolguy my response would be, what happens if something goes unexpectedly wrong with the long term job. – Jodrell Aug 24 '22 at 12:59
  • @Jodrell an "what if it goes unexpectedly wrong" is always a problem with every bit of code... what if your game logic's main loop suddenly throws? I don't take that as a reason to remove my main loop, but instead I hunt the bug down. isn't that really what we all mostly do in our day jobs? – Cool guy Aug 24 '22 at 13:18
  • @Coolguy, just makes the exception easier to catch and log. – Jodrell Aug 24 '22 at 13:28

1 Answers1

4

Are async methods' local variables Garbage Collected while the task is still running?

Today: no.

In the future: possibly.

Currently, any method transformation into a state machine (including both async methods and iterator blocks) hoists all local variables into a state machine on the heap, so they all share the same lifetime. If your async code needs local objects to be GCed before the method completes, then it should set the local variables to null.

This is not documented behavior and may change in the future.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • thanks. it's still very weird that there aren't proper documentations on this... I was thinking of making a never-ending iteration in a Unity game I was working on, and seems like never-ending async methods are not the answer. I guess the easy workaround would be to create another async method just to do temporary tasks, then the main async method would call the little tasks one by one – Cool guy Aug 23 '22 at 07:30
  • 2
    You *could* make a never-ending `async` method work as long as you set the local variables to `null` yourself. But it sounds like breaking into little tasks may be a better design anyway. – Stephen Cleary Aug 23 '22 at 14:40