In my application I need to schedule executing of some Actions with delay. It's like setTimeout in JavaScript. Also, when app execution ends I need to cancel all scheduled executions that have not been executed yet. So I have to call Task.Delay without await and pass CancellationToken into it. But if I do so, I face with memory leak: none of CancellationTokenSource+CallbackNode will be disposed until I call Cancel and Dispose of CancellationTokenSource from which I take CancellationTokens to pass to Task.Delay.
Minimal reproducible example:
CancellationTokenSource cts = new CancellationTokenSource();
for (int i = 0; i < 1000; i++)
{
Task.Delay(500, cts.Token).ContinueWith(_ => Console.WriteLine("Scheduled action"));
}
await Task.Delay(1000);
Console.ReadLine();
After executing this example, it leave 1000 of CancellationTokenSource+CallbackNode.
If I write cts.Cancel() after await Task.Delay(1000); leak does not appear

Why this leak happens? All Tasks was completed, so there should not be references to cts.Token. Disposing passed Task to continuation action does not help.
Also, if I await Task that schedule execution of action, leak does not appear.