title: Why does changing an XML schema and re-validating cause a memory leak?
body: <p>I recently uncovered a memory leak in an application I maintain for work, and I'm confused as to why the code produces a leak. I've pulled out the relevant code (with slight modifications) and provided it below.</p>
  
  <p>In our application, a given XML document could validate against one or more available schema files. Each schema file corresponds to a different version of the XML document as it has changed over time. We only care that the XML document validates against at least one schema. Each schema completely describes the contents of the XML document (they are not nested schema files).</p>
  
  <p>According to the ANTS memory profiler, it looks like the XmlDocument object is hording references to the previous schemas, even after the schema set has been cleared. <strong>Commenting out the call to Validate(), leaving everything else the same, will stop the leak.</strong></p>
  
  <p>I fixed the leak in our application by loading the schemas <strong>once</strong> at application initialization time, and swapping out which schema file is associated with the XML document until we find one that validates.</p>
  
  <p>The code below produces the memory leak, and I'm not sure why.</p>
  
  <pre><code>class Program
  {
      private static XmlDocument xmlDocument_ = new XmlDocument();
  
      static void Main(string[] args)
      {
          using (StreamReader reader = new StreamReader("contents.xml"))
          {
              xmlDocument_.LoadXml(reader.ReadToEnd());
          }
  
          XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
          xmlReaderSettings.CloseInput = true;
  
          while (true)
          {
              xmlDocument_.Schemas = new XmlSchemaSet();
  
              XmlReader xmlReader = XmlReader.Create("schema.xsd", xmlReaderSettings);
  
              xmlDocument_.Schemas.Add(XmlSchema.Read(xmlReader, null));
  
              xmlReader.Close();
  
              xmlDocument_.Validate(null);
          }
      }
  }
  </code></pre>