【问题标题】:Strings appear to be sticking around too long字符串似乎粘得太久了
【发布时间】:2011-02-03 14:42:46
【问题描述】:

简而言之,我有一个将平面数据文件转换为 XML 文件的应用程序。它通过填充对象然后将它们序列化为 XML 来做到这一点。

我遇到的问题是垃圾收集器似乎没有处理序列化的字符串。 3500 个记录文件在完成之前运行到 OutOfMemoryExceptions。确实有些可疑。

当我从组合中取出序列化并简单地传递一个空字符串时,内存消耗仍然如预期的那样,所以我已经排除了我的中间对象(平面文件和 xml 之间)是这里的问题的可能性。它们似乎按预期收集。

有人可以帮忙吗?如何确保正确处理这些字符串?

更新:一些示例代码

// myObj.Serialize invokes an XmlSerializer instance to handle its work    
string serialized = myObj.Serialize();
myXmlWriter.WriteRaw(serialized);

这基本上就是出现问题的地方——如果我不使用字符串serialized,内存问题也会消失,即使我仍在将平面文件转换为对象,一次一个.

更新 2:序列化方法

public virtual string Serialize()
{
      System.IO.StreamReader streamReader = null;
      System.IO.MemoryStream memoryStream = null;

      using (memoryStream = new MemoryStream())
      {
          memoryStream = new System.IO.MemoryStream();
          Serializer.Serialize(memoryStream, this);

          memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
          using (streamReader = new System.IO.StreamReader(memoryStream))
          {
              return streamReader.ReadToEnd();
          }
      }
}

【问题讨论】:

  • 一些sn-ps代码会有帮助...
  • 尝试使用 StringBuilder 并重用它,还有这么多记录可能将它们保存在文件系统/数据库中也可以
  • 我同意,但我在一家大公司工作,不能发布专有代码。
  • K Ivanov——我会试试 StringBuilder。至于记录的数量,我已经在序列化后将每条记录写入fs了。
  • 你在分配大的东西吗?我认为 LOH 碎片可能是一个问题 - stackoverflow.com/questions/686950/…

标签: c# string memory-management garbage-collection


【解决方案1】:

您需要确保它们没有在任何地方被引用。在抛出 OutOfMemoryException 之前,将运行 GC。如果它没有恢复那个记忆,那就意味着有东西还在保留它。就像其他人说的那样,如果您发布一些代码,我们可能会提供帮助。否则,您可以使用分析器或 WinDbg/SOS 来帮助确定您的字符串中存在什么。

【讨论】:

    【解决方案2】:

    确实很好奇。在每个序列化记录写入 XmlWriter 后,我添加了以下花花公子:

    if (GC.GetTotalMemory(false) > 104857600)
    {
         GC.WaitForPendingFinalizers();
    }
    

    您不知道吗,它一直在检查它,并且它正在毫无意外地处理,永远不会超过我设置的阈值。我觉得应该有更好的方法,但似乎代码执行得太快,垃圾收集器无法及时回收字符串。

    【讨论】:

      【解决方案3】:

      您是否有代码示例 - 您是如何创建这些字符串的?您是否在任何地方闯入非托管代码(这意味着您需要自己清理)。

      另一个想法是如何将平面数据文件转换为 XML。根据您构建文件的方式,XML 可能会有些繁重。如果您试图将整个对象保存在内存中,很可能(实际上很容易做到)内存不足。

      【讨论】:

        【解决方案4】:

        看起来您的方法确实可以清理为:

        public virtual string Serialize()
        {
            StringBuilder sb = new StringBuilder();
            using (StringWriter writer = new StringWriter(sb))
            {
                this.serializer.Serialize(writer, this);
            }
        
            return sb.ToString();
        }
        

        您无缘无故地创建了一个额外的MemoryStream

        但是,如果您要将字符串写入文件,那么为什么不直接将FileStream 发送到Serialize() 方法?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-12-21
          • 1970-01-01
          • 2010-12-01
          • 1970-01-01
          • 2015-01-07
          • 1970-01-01
          • 2016-08-10
          • 1970-01-01
          相关资源
          最近更新 更多