[System]: Fix memory leak in the web stack related to `Task.Delay` (partial fix of...
commit762af4e5b0ac4c25d04fc442560f5cb91081058c
authorMartin Baulig <martin.baulig@xamarin.com>
Wed, 4 Apr 2018 22:30:13 +0000 (4 18:30 -0400)
committerMarek Safar <marek.safar@gmail.com>
Fri, 6 Apr 2018 18:46:24 +0000 (6 20:46 +0200)
tree4e33713bf432567cc2f20063139cb8ef8cd3f6d4
parent0bc4732b72111cf3691480d2d911f0e178aae7f5
[System]: Fix memory leak in the web stack related to `Task.Delay` (partial fix of #7356).

Using `Task.Delay (timeout)` has the potential of possibly allocating and holding large
chunks of memory throughout the timeout period.  While this is not strictly speaking a
memory leak because those objects will eventually be disposed and garbage collected, it
can cause memory usage of apps to grow quite significantly in the short run.

The default timeout values are as follows:

* `HttpWebRequest.ReadWriteTimeout`: 5 minutes.

* `HttpWebRequest.Timeout`: 100 seconds.

* `ServicePointManager.MaxServicePointIdleTime`: 100 seconds.

And these values can be increased by the user.  This means that we're potentially holding
hundreds, maybe even thousands of timeout objects in memory for 5+ minutes.

This has now been fixed by using the `Task.Delay(int,CancellationToken)` constructor.

Note that disposing a `CancellationTokenSource` will not cancel it, so the following code
will still leak:

using (var cts = new CancellationTokenSource ()) {
Task.Delay (TimeSpan.FromDays (3), cts.Token);
// Work
}

To actually make the `Task.Delay` instance go away when we're done with it, we need to
use this pattern:

var cts = new CancellationTokenSource ();
try {
Task.Delay (TimeSpan.FromDays (3), cts.Token);
// Work
} finally {
cts.Cancel ();
cts.Dispose ();
}

We also cannot use `CancellationToken.CancelAfter()` for timeouts because unfortunately
some of the underlying framework code that we're using does not honor cancellation
requests - like for instance `NetworkStream`.

This is a partial fix for #7356.  While this commit significantly improves the problem,
there may be other unrelated issues left that needs to be investigated.
mcs/class/System/System.Net/HttpWebRequest.cs
mcs/class/System/System.Net/ServicePointScheduler.cs
mcs/class/System/System.Net/WebRequestStream.cs
mcs/class/System/System.Net/WebResponseStream.cs