title: Issues with list not getting garbage collected after use in mvc
body: <p>Backstory: I'm generating csv files as reports, and is testing to see what happens if multiple big reports are generated, this below should generate around 4 MB csv file, so if I called to get this report 2 times my pc would throttle at my 16 GB of ram, even after getting the files the program still uses all my ram, only by restarting the program can I clear up my ram. The ram is mostly used on boilerplate of the SMS class.</p>
  <p>My issue is that the tmp list is never cleared/cleaned up by the garbage collector, even after the controller call is finished, which ends in large amounts of ram getting used.</p>
  <p>I can see that the ram usage is only increasing when generating the tmp list not when creating the csv file</p>
  <p>The console output</p>
  <p><a href="https://i.stack.imgur.com/YebX3.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/YebX3.png" alt="enter image description here" /></a></p>
  <p>Visual studio Memory diagnostic after clicking download once</p>
  <p><a href="https://i.stack.imgur.com/dk10u.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/dk10u.png" alt="enter image description here" /></a></p>
  <p>Snapshot of memory</p>
  <p><a href="https://i.stack.imgur.com/eyPPu.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/eyPPu.png" alt="enter image description here" /></a></p>
  <pre><code>private static readonly Random random = new();
  private string GenerateString(int length = 30)
  {
      StringBuilder str_build = new StringBuilder();
      Random random = new Random();
  
      char letter;
  
      for (int i = 0; i &lt; length; i++)
      {
          double flt = random.NextDouble();
          int shift = Convert.ToInt32(Math.Floor(25 * flt));
          letter = Convert.ToChar(shift + 65);
          str_build.Append(letter);
      }
      return str_build.ToString();
  }
  
  [HttpGet(&quot;SMS&quot;)]
  public async Task&lt;ActionResult&gt; GetSMSExport([FromQuery]string phoneNumber)
  {
      Console.WriteLine($&quot;Generating items: {DateTime.Now.ToLongTimeString()}&quot;);
      Console.WriteLine($&quot;Finished generating items: {DateTime.Now.ToLongTimeString()}&quot;);
      Console.WriteLine($&quot;Generating CSV: {DateTime.Now.ToLongTimeString()}&quot;);
      var tmp = new List&lt;SMS&gt;();
      // tmp never gets cleared by the garbage collector, even if its not used after the call is finished
      for (int i = 0; i &lt; 1000000; i++)
      {
          tmp.Add(new SMS() { 
             GatewayName = GenerateString(),
             Message = GenerateString(),
             Status = GenerateString()
          });
      }
      // 1048574 is max, excel says 1048576 is max but because of header and seperater line it needs to be minussed with 2
      ActionResult csv = await ExportDataAsCSV(tmp, $&quot;SMS_Report.csv&quot;);
      Console.WriteLine($&quot;Finished generating CSV: {DateTime.Now.ToLongTimeString()}&quot;);
      return csv;
  }
  </code></pre>
  <pre><code>private async Task&lt;ActionResult&gt; ExportDataAsCSV(IEnumerable&lt;object&gt; listToExport, string fileName)
  {
      Console.WriteLine(&quot;Creating file&quot;);
      if (listToExport is null || !listToExport.Any())
          throw new ArgumentNullException(nameof(listToExport));
  
      System.IO.File.Delete(&quot;Reports/&quot; + GenerateString() + fileName);
      var file = System.IO.File.Create(&quot;Reports/&quot; + GenerateString() + fileName, 4096, FileOptions.DeleteOnClose);
  
      var streamWriter = new StreamWriter(file, Encoding.UTF8);
  
  
      await streamWriter.WriteAsync(&quot;sep=;&quot;);
      await streamWriter.WriteAsync(Environment.NewLine);
  
      var headerNames = listToExport.First().GetType().GetProperties();
      foreach (var header in headerNames)
      {
          var displayAttribute = header.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.DisplayAttribute),true);
          if (displayAttribute.Length != 0)
          {
              var attribute = displayAttribute.Single() as System.ComponentModel.DataAnnotations.DisplayAttribute;
              await streamWriter.WriteAsync(sharedLocalizer[attribute.Name] + &quot;;&quot;);
          }
          else
              await streamWriter.WriteAsync(header.Name + &quot;;&quot;);
      }
      await streamWriter.WriteAsync(Environment.NewLine);
  
      var newListToExport = listToExport.ToArray();
  
      for (int j = 0; j &lt; newListToExport.Length; j++)
      {
          object item = newListToExport[j];
          var itemProperties = item.GetType().GetProperties();
          for (int i = 0; i &lt; itemProperties.Length; i++)
          {
              await streamWriter.WriteAsync(itemProperties[i].GetValue(item)?.ToString() + &quot;;&quot;);
          }
          await streamWriter.WriteAsync(Environment.NewLine);
      }
      Helpers.LogHelper.Log(Helpers.LogHelper.LogType.Info, GetType(), $&quot;User {User.Identity.Name} downloaded {fileName}&quot;);
      await file.FlushAsync();
      file.Position = 0;
      
      return File(file, &quot;text/csv&quot;, fileName);
  }
  </code></pre>
  <pre><code>public class SMS
  {
      
  
      [Display(Name = &quot;Sent_at_text&quot;)]
      public DateTime? SentAtUtc { get; set; }
  
      [Display(Name = &quot;gateway_name&quot;)]
      public string GatewayName { get; set; }
  
      [Display(Name = &quot;message_title&quot;)]
      [JsonProperty(&quot;messageText&quot;)]
      public string Message { get; set; }
  
      [Display(Name = &quot;status_title&quot;)]
      [JsonProperty(&quot;statusText&quot;)]
      public string Status { get; set; }
  }
  </code></pre>