.NET中的内存问题

时间:2010-09-24 12:44:41

标签: c# .net

我有一个C#服务,它侦听XML消息的队列,接收它们,使用XSLT处理它们并将它们写入数据库。 它每天处理大约60K个消息,每个消息大约1Mb。空闲时的内存下降到100MB,这真的很好。 但是最近我开始处理大小为12 MB的消息。它确实会耗尽内存,即使在空闲时它也有大约500MB的内存。任何建议为什么这可能是一个问题?我认为没有内存泄漏,因为它会在处理了这么多(60K消息1MB)之后浮出水面。

7 个答案:

答案 0 :(得分:7)

看起来非常好。为什么你认为这是一个问题?

垃圾收集器最终将释放未使用的内存,但这并不意味着只要您的服务空闲就会发生这种情况。

Raymond Chen撰写了一篇很好的文章,解释了垃圾收集的基本思想:

  

<强> Everybody thinks about garbage collection the wrong way

然而 - 但这是对您的问题中给出的信息的纯粹推测 - 可能存在与XSLT中的扩展方法相关的内存泄漏。如果在每次转换新的XML文档时重新编译样式表,扩展方法可能会导致问题。修复很简单:编译完成后,缓存样式表。

答案 1 :(得分:5)

SIR!放下任务经理并走出去。认真。 .NET中的内存管理并未针对最小的占用空间进行调整。它针对效率进行了调整。它将保留在内存中而不是将其释放回系统。除非存在实际问题(OOM异常,系统问题),否则要抵制小心记忆的诱惑。

答案 2 :(得分:3)

您使用什么衡量记忆?有很多可能的措施,其中没有一个真正意味着“用过的记忆”。使用虚拟内存,共享图像等事情并不简单。

  

即使在空闲时也有大约500MB的内存

大多数进程(我认为这包括.NET)一旦分配给进程,就不会将内存释放回操作系统。但如果它没有被使用,它将从物理内存中分页,允许其他进程使用它。

  

开始处理大小为12 MB的邮件

如果将XML文档扩展为对象模型(例如XmlDocument),则需要更多内存(许多链接到其他节点)。要么看一个不同的模型(XDocumentXPathDocument都是较轻的权重),或者更好的是,用XmlReader处理XML,因此永远不会有完全扩展的对象模型。

答案 3 :(得分:2)

首先,在系统中添加一些内容,以允许您手动调用垃圾收集以进行调查。除非供应短缺,否则CLR不一定会将内存返回给操作系统。当系统处于静止状态时,您应该使用此机制手动调用垃圾收集,以便您可以查看内存是否会降低。 (您应该两次调用GC.Collect(2)以确保实际收集具有终结器的对象,而不是最终确定。)

如果在完整的GC之后内存下降到静止级别,那么你没有问题:只是.NET没有主动解除内存。

如果内存没有下降,那么你会有某种泄漏。由于您的消息很大,这意味着它们的文本表示可能最终会出现在大对象堆(LOH)上。这个特定的堆没有被压缩,这意味着泄漏这个内存比使用其他堆更容易。

需要注意的一点是字符串实习:如果你是手动实习字符串,这可能导致LOH碎片。

答案 4 :(得分:1)

很难说可能是什么问题。在调查内存问题时,我使用Ants Memory Profiler取得了成功。

答案 5 :(得分:1)

与思想相反我认为没有内存泄漏;我想profile记忆。

答案 6 :(得分:0)

我会检查你的事件处理程序。如果您在完成后不小心分离它们,似乎很容易创建GC不会收集的对象引用。
我不知道这是最好的做法(因为开始和取消事件处理的责任应落到订阅者身上),但我已经走了实现IDisposable并使用显式委托字段实例创建事件的路线。在处理时,该字段可以设置为null,这有效地分离所有订阅。

类似的东西:

public class Publisher
    : IDisposable
{
    private EventHandler _somethingHappened;
    public event EventHandler SomethingHappened
    {
        add { _somethingHappened += value; }
        remove { _somethingHappened -= value; }
    }
    protected void OnSomethingHappened(object sender, EventArgs e)
    {
        if (_somethingHappened != null)
            _somethingHappened(sender, e);
    }

    public void Dispose()
    {
        _somethingHappened = null;
    }
}

除非(我不知道你对发布者有多少控制权),你可能需要小心分离订阅者不需要的处理程序:

public class Subscriber
    : IDisposable
{ 
    private Publisher _publisher;
    public Publisher Publisher
    {
        get { return _publisher; }
        set {
            // Detach from the old reference
            DetachEvents(_publisher);
            _publisher = value;
            // Attach to the new
            AttachEvents(_publisher);
        }
    }

    private void DetachEvents(Publisher publisher)
    {
        if (publisher != null)
        {
            publisher.SomethingHappened -= new EventHandler(publisher_SomethingHappened);
        }
    }
    private void AttachEvents(Publisher publisher)
    {
        if (publisher != null)
        {
            publisher.SomethingHappened += new EventHandler(publisher_SomethingHappened);
        }
    }

    void publisher_SomethingHappened(object sender, EventArgs e)
    {
        // DO STUFF
    }

    public void Dispose()
    {
        // Detach from reference
        DetachEvents(Publisher);
    }
}