Let\'s look at the following snippet which shows the problem.
class Program
{
static void Main(string[] args)
{
var task = Start();
T
sync is simply not reachable from any GC root. The only reference to sync is from the async state machine. That state machine is not referenced from anywhere. Somewhat surprisingly it is not referenced from the Task or the underlying TaskCompletionSource.
For that reason sync, the state machine and the TaskCompletionSource are dead.
Adding a GC.KeepAlive does not prevent collection by itself. It only prevents collection if an object reference can actually reach this statement.
If I write
void F(Task t) { GC.KeepAlive(t); }
Then this does not keep anything alive. I actually need to call F with something (or it must be possible for it to be called). The mere presence of a KeepAlive does nothing.