3

I have a windows service application built with .Net framework 4.5. This service when kept running for a longer duration keeps on accumulating memory and slowly gradually it takes up to 100-200MB. The role of this service on broad level is to make some GET call every minute and then act on the response(kind of polling). I am using a single instance of HttpClient for all the requests the anomaly I am seeing after analyzing memory dumps is the presence of _SSL streams that are not getting disposed of, I believe these objects are getting used internally inside HttpClient library. Also, another thing to point out is this scenario is occurring only when the service is not able to reach to the API, when API is reachable then there is no abrupt increase in memory and _SSLStream objects are not present in memory dumps. In the code snippet as shown below GetDataAsync is called by TimerObject every minute What could be the possible reason for the same?

Sample code snippet

public class Sample //This class has a single instance in the app maintained by the Unity container
{
private HttpClient Client {get;set;}

public Sample() {
  System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; //To support both TLS1.1 and 1.2
  this.Client = new HttpClient();
}

private async Task < string > GetDataAsync(Uri completeUrl) {

    HttpRequestMessage httpRequestMessage = new HttpRequestMessage {
      Method = HttpMethod.Get,
        RequestUri = completeUrl,
    };
    HttpResponseMessage responseMessage = null;
  

      httpRequestMessage.Headers.Add("Authorization", new AuthenticationHeaderValue("Bearer", "SomeAccessToken");

        try {
          responseMessage = await Client.SendAsync(httpRequestMessage);
        } catch (Exception ex) {
          throw ex;
        }
        finally
        {
            httpRequestMessage?.Dispose();
            responseMessage?.Dispose();
        }
}
}

enter image description here Detailed view of SSL stream object enter image description here

Shubham Awasthi
  • 159
  • 1
  • 13
  • I haven't investigated this issue, but my first thought would be to **not** reuse the `HttpClient`, and instead create a new instance each time a request needs to be made, and dispose of it afterwards. If the calls are made every minute, then the overhead should be negligible. Have you tried this approach? – Lars Kristensen Jul 05 '22 at 14:42
  • Since connection pooling is used by the httpclient, and the docs say that a new socket is pooled for each successful request, it could be that all of your the rapid fire failures are instantiating new sockets and related artifacts, whereas, successful http requests reuse existing connections when available. – Ross Bush Jul 05 '22 at 14:42
  • @Lars Kristensen- Yes if i create new http client for every request then even for successful requests i am seeing this behavior. – Shubham Awasthi Jul 05 '22 at 14:46
  • @RossBush is there a way where we can prevent creation of new sockets for failure requests? – Shubham Awasthi Jul 05 '22 at 14:46
  • @LarsKristensen in general this is how `HttpClient` _should_ not be used, especially in .NET Framework. – Guru Stron Jul 05 '22 at 15:28
  • 1
    I'm not convinced you have a memory leak. A process to run in 100-200MB is tiny. Not all memory growth is a leak. GC is indeterminate and will certainly not over trigger for a process using 200MB but has e.g. 1GB available to it. – JohanP Jul 06 '22 at 00:13
  • @JohanP the point is these SSLStreams objects are never disposed of by GC – Shubham Awasthi Jul 06 '22 at 08:31
  • @GuruStron I'm not sure if you are referring to my suggestion or OP's setup - in either case, can you explain why it should / should not be used in that way? – Lars Kristensen Jul 06 '22 at 10:46
  • 2
    @LarsKristensen I'm basing my opinion on [this](https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/) and [this](https://stackoverflow.com/a/67128271/2501279). .NET Core approach is to use [`IHttpClientFactory`](https://learn.microsoft.com/en-us/dotnet/api/system.net.http.ihttpclientfactory?view=dotnet-plat-ext-6.0) which should handle everything internally. – Guru Stron Jul 06 '22 at 10:55
  • @ShubhamAwasthi if these sslStreams are part of connection pooling, why would the GC dispose of them? Try setting the `ConnectionLeaseTimeout` to a lower level and see if that makes a difference `ServicePointManager.FindServicePoint(url).ConnectionLeaseTimeout` – JohanP Jul 06 '22 at 23:04
  • @LarsKristensen Creating a HttpClient per request is an anti-pattern. *HttpClient is intended to be instantiated once and reused throughout the life of an application.* <- from the official [HttpClient Class](https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient). – tymtam Jul 07 '22 at 10:07
  • @Tymtam Thanks. In the first article that @GuruStron links to, you can see that that remark was not always part of the documentation (at least not in 2016 when the article was published), and because `HttpClient` implements `IDisposable` interface, developers are used to thinking that if they wrap its constructor in a using-statement, its resources will be disposed when the block is exited - which apparently isn't the case for HttpClient. – Lars Kristensen Jul 07 '22 at 11:38

0 Answers0