This is asked more out of curiosity than with regards to any real-world problem.
Consider the following code:
void Main()
{
FAsync().Wait();
}
The compiler turns your async method into a state machine struct. The struct is created firstly on the stack. When you await an uncompleted task (otherwise it continues running synchronously and will cause an overflow of the stack) that state machine is boxed and moved to the heap.
For example this method:
public async Task M()
{
}
is turned into this state machine:
private struct d__0 : IAsyncStateMachine
{
public int <>1__state;
public AsyncTaskMethodBuilder <>t__builder;
void IAsyncStateMachine.MoveNext()
{
try
{
}
catch (Exception exception)
{
this.<>1__state = -2;
this.<>t__builder.SetException(exception);
return;
}
this.<>1__state = -2;
this.<>t__builder.SetResult();
}
[DebuggerHidden]
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
this.<>t__builder.SetStateMachine(stateMachine);
}
}
So, in "traditional" recursion the state for each iteration is stored on the stack so too many iterations can overflow that memory. In an async method the state is stored on the heap and it may overflow as well (though it's usually much bigger).