【问题标题】:.net OutOfMemory exception.net OutOfMemory 异常
【发布时间】:2009-05-21 12:07:34
【问题描述】:

在对我正在为 Windows Mobile 编写的类库进行一些最终测试时 (使用 Compact Net Framework 2.0),我遇到了 OOM 异常。

基本上,我的库首先加载一个字典文件(一个带有单词列表的普通文本文件),然后加载另一个基于字典的文件(我称之为 KeyMap),其大小与之前加载的字典大致相同.

在我尝试加载大小约为 2.7MB 的西班牙语词典之前,上述文件一切正常(使用模拟器和我的真实设备)。到目前为止,我使用的其他语言词典没有任何 OOM 异常,每个词典大约有 1.8MB。使用西班牙语词典,我可以毫无问题地加载第一个文件,但是当我尝试读取第二个文件时,我得到了 OOM 错误。

下面我已经编写了我正在使用的代码。基本上我读取文件并将其内容分配给字符串变量(DictData 和 TextKeyMap)。然后我对字符串变量进行拆分以将内容传递给字符串数组(Dict 和 KeyMap)。

'Loading Dictionary works
Dim ReadDictionary As StreamReader = New StreamReader(DictPath, Encoding.UTF8)
   DictData = ReadDictionary.ReadToEnd()
            ReadDictionary.Close()
            Dict = DictData.ToString.ToUpper.Split(mySplitSep.ToCharArray) 'mySplitSep=chr(10)
            DictData = "" 'perhaps "nothing" is better

 'Loading KeyMap gives me error
 Dim ReadHashKeyMap As StreamReader = New StreamReader(HashKeyMapPath, Encoding.UTF8)
    TextKeyMap = ReadHashKeyMap.ReadToEnd() '<-- OOM-error
            ReadHashKeyMap.Close()
            KeyMap = TextKeyMap.ToString.Split(mySplitSep.ToCharArray) 'mySplitSep=chr(10)
            TextKeyMap = "" 'perhaps "nothing" is better 

我是一个没有专业知识的业余程序员,所以我上面显示的代码可能是 改善。我没有使用 ReadToEnd,而是尝试读取 For 循环中的每一行,但我得到了 同样的错误(它也很慢)。

我认为该错误是由于 Windows Mobile 中 32MB 的连续内存限制所致。

你们中的任何人都可以帮助我,或许可以提出一些替代解决方案?也许 问题是由于我上面显示的蹩脚代码?怎么样,加载第二个文件 另一个线程?这行得通吗?

我能得到的所有帮助将不胜感激。

编辑:前段时间我问了一个类似的问题(here),但这个问题与处理字节接收更相关,并使用块来解决。在这种情况下,我正在处理字符串。

Edit2:这个库是一个拼写检查库。它工作得很好,并实现了一些相当先进的技术,例如 Soundex 和 DoubleMetaPhone 算法。到目前为止,唯一的主要问题是上面提到的问题,其中包含一个巨大的西班牙语文本文件。其他词典都还行。更多信息请见this link

【问题讨论】:

  • 您能给我们举个例子说明文件中的内容吗?
  • 或许相关且有用? --> stackoverflow.com/questions/678025/…
  • Eric:这只是一个单词列表:“car”“cars”“cart”等(每个单词单独一行)
  • @moster67 - 那么哈希键映射是一样的吗?我想我想弄清楚这两个文件是如何相关的,以及如何将其压缩为一个文件而不是两个文件。
  • EricP:KeyMap 文件类似于字典的索引文件。你可以称它为 HashKeyMap。 KeyMap 文件是使用 Soundex 算法创建的。虽然单词表的结构是“word” + chr(10) + “word”等,但 KeyMap 文件如下: 代码(由 Soundex 生成):来自单词表的所有单词都具有这种发音(代码)。我已经尝试创建一个读取字典的 HashKeyMap(而不是使用“第二个文件”),但它比较慢,因为它必须被排序和加载)

标签: .net string windows-mobile memory-management compact-framework


【解决方案1】:

由于你没有说你使用这个文件是什么,我假设你只是出于某种原因搜索一个词。

首先,尝试将完整文件加载到内存中可能不是一个好主意。相反,在文件中搜索您需要的数据(单词)可能会更有效率,并且可能还会在内存中保留某种索引信息以加快速度。

由于您尝试搜索的数据只是一个单词列表,因此最好扫描文件并在字典中记录单词第一个字母发生变化的位置。例如 A 从第 0 行开始; B 从第 200 行开始; C 从第 300 行等开始。使用这两条信息来填充您的字典;字母是键,行号是值。实际上,字典成为单词列表文件的高级索引。这本词典也很小。

然后,当您开始搜索一个单词时,使用该单词的第一个字母来搜索字典。这将为您提供文件中以该字母开头的单词所在的行号。使用行号(重新)打开文件并通过将流指针移动到目标行直接转到 word 文件中的该行。然后从那里搜索目标词。或者顺序搜索,一次一行(不推荐它会很慢,但更容易编码)。或者,使用binary chop 搜索单词(更快,但更难编码)。尽管对于后者,您还需要知道以目标字母开头的单词在文件中的停止位置,因为您将搜索文件的一部分。我还建议您在文件中进行单词搜索,而不是将所有这些单词加载到内存中,否则您可能会回到开始出现 OOM 错误的位置。

如果您不确定,请在此处发表评论,我会尽力回答。

祝你好运

【讨论】:

  • 输入好! BinarySearch 已被随时随地使用。虽然第一个文件(单词列表)必须按照我的代码所示加载(我的库中的其他算法需要),但你的想法仍然很好,尤其是关于第二个文件,这意味着我可以避免加载第二个文件并仅在需要时加载/访问相同的内容。当然,这将涉及大量文件访问,并且可能会造成相当大的性能损失,但仍然......我会试一试!谢谢!
  • 请参阅我的编辑2以获取有关图书馆的一些额外信息
  • 感谢您的反馈。你有机会投票给我的答案吗? ;-) 关于第二个文件。您可以尝试在后台线程上搜索文件,这至少应该让您的 UI 保持响应。
【解决方案2】:

您似乎没有足够的内存来同时将所有文件中的所有文本保存在内存中。您可能需要想出一个策略来缓存有限的文件子集,并且足够智能以在请求的内容不在缓存中时返回文件。

如果练习的全部目的是您不必返回文件(例如,建立某种索引),您也可以尝试变得“聪明”并提出替代表示对于内存中的文本,它利用了大多数西方语言的可压缩性。

【讨论】:

  • GregD:KeyMap 文件实际上是字典的索引文件。我可以将它拆分成更小的部分,并在需要时加载所需的部分,但这会减慢检索建议的拼写检查过程,尤其是在这种情况下,因为它在内存和硬件资源有限的 Windows Mobile 上运行。
【解决方案3】:

我会说有问题的行是这一行:

Dict = DictData.ToString.ToUpper.Split(mySplitSep.ToCharArray)

GC 无法跟上这条简单线后面临时对象的创建。 “ToUpper”正在创建原始字符串的副本,“Split”正在从该副本中创建一个新数组(并且可能会为拆分算法本身使用更多内存)。对了,“ToString”的调用是没用的,DictData已经是一个字符串了吧?

就个人而言,我会从流中逐块读取,然后逐块拆分,放入列表。但是如果你想保持你的代码简短,试试这个,你永远不会知道:

DictData = ReadDictionary.ReadToEnd()
ReadDictionary.Close()
DictData = DictData.ToUpper()
GC.Collect()
Dict = DictData.Split(mySplitSep.ToCharArray)
DictData = Nothing
GC.Collect()

我从来没有发现调用 GC.Collect 是一个好的解决方案。调用它通常意味着“应该做一些更好的事情”。但是 .NET CF 下的内存管理有时会很痛苦。

【讨论】:

  • slimCODE:我告诉过你我的代码很糟糕!你是对的 - DictData 是一个字符串,但要转换为大写,我必须添加“.To.String”才能获得“.To.Upper(使用 Intellisense)或者我错了。我可以'现在验证。
  • slimCode:您能否详细说明您关于“将片段分割成列表”的想法。我不明白你的意思。至于你的代码建议,我会试试的。谢谢!”
  • slimCODE:我尝试了您的代码,将相同的代码应用于第一个和第二个文件,但不幸的是我仍然遇到 OOM 异常。
猜你喜欢
  • 1970-01-01
  • 2013-12-09
  • 2023-04-03
  • 1970-01-01
  • 2015-07-28
  • 2018-06-18
  • 2015-04-25
  • 2016-04-26
  • 2014-07-15
相关资源
最近更新 更多