代码审查:OutOfMemoryException问题

时间:2010-02-12 15:54:36

标签: c# .net out-of-memory

我不断收到下面代码中的'System.OutOfMemoryException'。我无法弄清楚内存泄漏的位置,如果有人能够解释我做错了什么,这将是一个很大的帮助。谢谢!

lock ((_tabs))
{
    System.IO.StreamReader sr = null;
    System.IO.MemoryStream ms = null;
    try
    {
        Type[] t = { typeof(tsgPublicDecs.tsgClsTab) };
        System.Xml.Serialization.XmlSerializer srl = new System.Xml.Serialization.XmlSerializer(typeof(ArrayList), t);
        ms = new System.IO.MemoryStream();
        srl.Serialize(ms, _tabs);
        ms.Seek(0, 0);
        sr = new System.IO.StreamReader(ms);
        return sr.ReadToEnd();
    }
    finally
    {
        if (((sr != null)))
        {
            sr.Close();
            sr.Dispose();
        }
        if (((ms != null)))
        {
            ms.Close();
            ms.Dispose();
        }
    }
}

编辑:回答几个问题:

  • _tabs没有填充任何东西(这带来了许多其他问题,为什么它甚至被使用,但我需要问开发人员为此编写它)
  • 抛出错误的行是'srl.Serialize(ms,_tabs);'
  • 这个错误是随机的,我自己无法复制它,但让它运行几天就会被抛出。因此,我无法(不知道如何)获取超出错误的任何信息。

编辑2: 感谢所有的投入。添加使用并寻找其他可能的内存泄漏似乎是最好的方法。很高兴看到人们可以多快帮忙!

6 个答案:

答案 0 :(得分:3)

你确定问题出在这里吗?

你不是在其他地方泄露记忆吗?

OutOfMemoryException可以从任何地方抛出内存分配,这可能只是巧合,它发生在这里。

尝试在内存分析器中分析应用程序,看看是否持有一些会导致内存“泄漏”的引用。

尝试尽可能多地从测试计算机中删除RAM(取决于操作系统,尝试在XP上降至256/128 MB)并多次运行重复用例(不一定只是运行此操作的用例)码)。

答案 1 :(得分:0)

根据_tabs的大小,您通过sr.ReadToEnd()读取整个序列化流的事实可能会导致它。

答案 2 :(得分:0)

它正在为一两个使用块而尖叫。

lock ((_tabs))
{
        Type[] t = { typeof(tsgPublicDecs.tsgClsTab) };
        System.Xml.Serialization.XmlSerializer srl = new System.Xml.Serialization.XmlSerializer(typeof(ArrayList), t);

        using ( System.IO.MemoryStream ms = new System.IO.MemoryStream())
        {  
           srl.Serialize(ms, _tabs);
           ms.Seek(0, 0);

           using (System.IO.StreamReader sr = new System.IO.StreamReader(ms))
           {
            return sr.ReadToEnd();
           }
        }


}

答案 3 :(得分:0)

  1. 像其他人说的那样,我会怀疑_tabs。

  2. 将Visual Studio设置为在抛出的异常时中断并检查其大小。

  3. 如果您要简单地使用Dispose,为什么不使用嵌套的'using'块而不是finally块?

  4. 当出现内存不足异常时,正在运行多少个线程?您的代码块可能在内存已被使用时挂起。

答案 4 :(得分:0)

试试这个.. 这在SnippetCompiler中运行。如果它不起作用,那么tsgClsTab类中有一个循环引用。 并且,是的,查找'using'; - )

using System;
using System.Collections;
using System.IO;
using System.Xml.Serialization;

public class MyClass
{
    public static void RunSnippet()
    {
        var _tabs = new ArrayList();

        _tabs.Add(new tsgClsTab(1));
        _tabs.Add(new tsgClsTab(2));
        _tabs.Add(new tsgClsTab(3));
        _tabs.Add(new tsgClsTab(4));

        lock ((_tabs))
        {
            StreamReader sr = null;
            MemoryStream ms = null;
            try
            {
                var srl = new XmlSerializer(typeof (ArrayList),
                                            new Type[] {typeof (tsgClsTab)});
                ms = new MemoryStream();
                srl.Serialize(ms, _tabs);
                ms.Seek(0, 0);
                sr = new StreamReader(ms);
                Console.WriteLine(sr.ReadToEnd());
            }
            finally
            {
                if (((sr != null)))
                {
                    sr.Close();
                    sr.Dispose();
                }
                if (((ms != null)))
                {
                    ms.Close();
                    ms.Dispose();
                }
            }
        }
    }

    #region Helper methods

    public static void Main()
    {
        try
        {
            RunSnippet();
        }
        catch (Exception e)
        {
            string error = string.Format("---\nThe following error occurred while executing the snippet:\n{0}\n---",
                                         e.ToString());
            Console.WriteLine(error);
        }
        finally
        {
            Console.Write("Press any key to continue...");
            Console.ReadKey();
        }
    }

    #endregion

    #region Nested type: tsgClsTab

    public class tsgClsTab
    {
        public tsgClsTab()
        {
        }

        public tsgClsTab(int id)
        {
            Id = id;
        }

        public int Id { get; set; }
    }

    #endregion
}

输出

<?xml version="1.0"?>
<ArrayOfAnyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <anyType xsi:type="tsgClsTab">
    <Id>1</Id>
  </anyType>
  <anyType xsi:type="tsgClsTab">
    <Id>2</Id>
  </anyType>
  <anyType xsi:type="tsgClsTab">
    <Id>3</Id>
  </anyType>
  <anyType xsi:type="tsgClsTab">
    <Id>4</Id>
  </anyType>
</ArrayOfAnyType>

答案 5 :(得分:0)

这是另一个建议,如果你可以摆动它。使用强类型泛型替换_tabs'声明(我假设声明为ArrayList somwhere):

old:private ArrayList _tabs = new ArrayList(); 新:private List<tsgPublicDecs.tsgClsTab> _tabs = new List<tsgPublicDecs.tsgClsTab>();

同样调整XmlSerializer实例化。

话虽如此,经过一些非常基本的测试后,我无法获得任何OOM异常。以下是其他人所说的简化使用方法:

    lock (_tabs)
    {
        Type[] t = { typeof(tsgPublicDecs.tsgClsTab) };
        System.Xml.Serialization.XmlSerializer srl = new System.Xml.Serialization.XmlSerializer(typeof(ArrayList), t);
        using (System.IO.Stream ms = new System.IO.MemoryStream())
        {
            srl.Serialize(ms, _tabs);
            ms.Seek(0, 0);
            using (System.IO.TextReader sr = new System.IO.StreamReader(ms))
            {
                return sr.ReadToEnd();
            }
        }
    }

编辑:好好猜测一下?我能够发生OutOfMemoryException。但只有一万个这些项目的arraylist,每个项目都参考前一个项目。所以当它落到它时它是一个非常复杂的对象图,这可能就是你遇到的。