抛出了类型'System.OutOfMemoryException'的异常

时间:2011-02-05 15:17:47

标签: .net out-of-memory

我突然得到了在不同机器上运行的两个程序的内存异常错误,即使它看起来有足够的内存,它仍然显示出来。我正在程序中创建多个线程,所以不确定这是否适合这个论坛,但它可能是与visual studio相关的东西,或者它肯定是内存问题。一个程序在我的桌面上使用visual studio 2008和2 gb ram运行。另一个使用visual basic 2008 express在运行4 GB RAM的Windows 2003服务器上运行。 现在,模块将一个大的xml文件读入一个字符串,然后拆分并存储在一个字符串数组中。现在块的数量可以达到10000.现在我知道这很大,但我已经运行了一个多月了,从来没有遇到过这个问题。我注意到的另一个可能的相关问题是我的硬盘驱动器上的空间不足,但很快就通过清理解决了这个问题。哦,是的,我的机器的处理器是一个设置在2.13 GHZ的双核心。 它是一个控制台程序,可以生成多个Web请求,但内存问题只出现在一个特定模块中,正如我上面所解释的那样。

Public Shared Function textLoad(ByVal _html As String) As Boolean
    Try 
            //_html is the filestream that was read in

        Dim defaultHeading = "xmlns:gnip=""http://www.gnip.com/schemas/2010"" xmlns=""http://www.w3.org/2005/Atom"""
        Dim header_of_xml As String = "<?xml version=""1.0"" encoding=""utf-8""?>" & vbNewLine & "<entry " & defaultHeading & ">"
        Dim footer_of_xml As String = "</entry>"
        Dim entry As String = String.Empty
        Dim xrs As XmlReaderSettings = New XmlReaderSettings()
        Dim dupeArray As New ArrayList
        Dim stringSplitter() As String = {"</entry>"}

        //split the file content based on the closing entry tag
        sampleResults = Nothing
        sampleResults = _html.Split(stringSplitter, StringSplitOptions.RemoveEmptyEntries)
        entryResults.Clear()

        If getEntryId(sampleResults) Then
           // the following loops seem clumsy but I wanted to dedupe the lists to //ensure that I am not adding duplicate entries and I do this by going to the getEntryID //method and extracting the ids and then comparing them below 

            For i As Integer = 0 To sampleResults.Count - 1
                For j As Integer = 0 To idList.Count - 1
                    If sampleResults(i).Contains(idList.Item(j)) AndAlso Not dupeArray.Contains(idList.Item(j)) Then
                        dupeArray.Add(idList.Item(j))
                        entry = sampleResults(i)

我确实看过taskmanager来识别这个程序使用的资源,这是正在发生的事情:

Parser.exe CPU = 34                MEM用量= 349,500 K

没有其他密集的东西正在运行

修改 _ -

准确找出问题的来源:

**sampleResults = _html.Split(stringSplitter, StringSplitOptions.RemoveEmptyEntries)**

任何人都可以注意到这个问题吗?

5 个答案:

答案 0 :(得分:9)

Split方法为返回数组中的每个元素分配字符串对象的内存。如果你要遇到内存问题,它就会出现在那条线上。由于您在一个可能碎片堆上同时为可能10,000个大字符串分配内存,因此您可能无法找到足够的连续空间来分配下一个字符串(这会产生结果)并不奇怪在您遇到的例外中)。你真的需要所有这些字符串吗?或者你可以做这样的循环:

  1. 一次读取一行(或放入缓冲区)以构建字符串。
  2. 当你找到第一个“大块”时停止。
  3. 从块中获取所需的信息。 (我假设你不需要整件事,你只是想从中得到一些东西吗?)。
  4. 继续阅读html(在#1处重启),将其读入相同的字符串变量,以便第一个块可以收集垃圾。
  5. 如果您能以这种方式实施解决方案,那么您的问题就会消失。

答案 1 :(得分:4)

请注意,OOM并不意味着您已经超出了物理RAM,但是您无法将所需大小的新内存块放入地址空间。

有很多可能的原因

  • 堆碎片
  • 32位进程的2GB限制
  • 在配置
  • 中设置的最大内存大小

然后有假的OOM例外。例如,GDI +为包括无效参数在内的各类问题返回内存不足错误。这些也变成了OOM例外。

答案 2 :(得分:2)

您是否尝试使用.NET Performance Counters运行应用程序时分析内存使用情况?您可以启动性能监视器(在Windows 2008 R2中,它位于管理工具&gt;性能监视器下),并在.NET内存下添加计数器,用于Gen 0堆大小,Gen 1堆大小,Gen 2堆大小和大对象堆大小。在应用程序运行时,您可以使用这些计数器查看内存分配的位置。

由于您正在使用字符串,因此请务必考虑在大对象堆上分配超过85,000字节的字符串。所有其他堆都被垃圾收集器压缩,但出于性能原因,大对象堆永远不会被压缩。这基本上意味着当GC处理时,GC将从LOH中清除对象,但其余对象永远不会从LOH上的原始位置移动。 CLR的这种行为可能导致LOH碎片并最终导致OOM异常。

以下是LOH分支如何导致OOM异常的简单示例。假设我们在LOH上有100个总单位,我们分配10个单位然后分配5个单位,剩下85个。 CLR必须连续分配内存,因此在我们的示例中,我们现在占用了LOH的前15个单元。我们尝试为一个非常大的对象分配86个单元,我们得到一个OOM异常。意识到我们没有足够的空间,我们清除了我们首先分配的10个单位,剩下95个单位可用。我们再次尝试分配86个单位,但由于CLR没有压缩LOH并且CLR要求86个连续单位,我们仍然会得到OOM异常。在我们清除第二个5个单位之前,我们将无法分配86个单位。这是一个过于简单的示例,但如果您使用Google LOH碎片或查看此article,您可以获得更深入的解释。

我不能确定这是否是您遇到的问题,但我肯定会检查性能监视器以查看您的内存分配位置。如果你知道你正在分配超过85,000字节的字符串或其他对象,那么请尝试将它们进一步拆分,以免它们远离LOH。

答案 3 :(得分:1)

我遇到了同样的问题。 考虑转向64位操作系统。 我有一些技巧来推迟这个例外:

1。 最重要的是当使用字符串(特别是长)时 使用ref从一种方法转移到另一种方法。 它显着降低了内存和性能。

2。 您可以使用AppDomain存储数据。 这使你的记忆能力加倍。

3。 只要你可以 - 而不是创建对象和字符串(WebRequests / Response),重新使用相同的memoryStream或缓冲区。 分配最大尺寸的一个(即使是最大预期尺寸* 2)。 Stream / StringBuilder / strings / classes / Buffers的分配(使用new) 窒息堆。

答案 4 :(得分:0)

这篇文章可能很有用,它描述了一些可以抛出异常的东西:

http://kb.insideofthefuture.com/Assuntos/outofmemoryexception.htm