исключение .net OutOfMemory - PullRequest
2 голосов
/ 21 мая 2009

Выполняя последние тесты библиотеки классов, которую я пишу для Windows Mobile (используя Compact Net Framework 2.0), я столкнулся с OOM-исключением.

По сути, моя библиотека загружает сначала файл словаря (обычный текстовый файл со списком слов), а затем другой файл, основанный на словаре (я называю это KeyMap), размер которого примерно равен размеру ранее загруженного словаря. ,

Все работало нормально (с помощью эмулятора и моего реального устройства) с указанными выше файлами, пока я не попытался загрузить испанский-словарь, размер которого составляет примерно 2,7 МБ. Другие языковые словари, которые я использовал до сих пор без каких-либо OOM-исключений, составляют примерно 1,8 МБ каждый. С помощью испанского словаря я могу загрузить первый файл без проблем, но когда я пытаюсь прочитать второй файл, я получаю ошибку OOM.

Ниже я написал код, который я использую. В основном я читаю файлы и присваиваю их содержимое строковой переменной (DictData и TextKeyMap). Затем я делю Split на строковую переменную для передачи содержимого в строковый массив (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, но я получил та же самая ошибка (это было также медленнее).

Я предполагаю, что ошибка связана с ограничением 32 МБ непрерывной памяти в Windows Mobile.

Кто-нибудь из вас может мне помочь, возможно, предложив несколько альтернативных решений? Может быть проблема из-за моего дерьмового кода, показанного выше? Как насчет загрузки второго файла в другая нить? Может ли это работать?

Любая помощь, которую я могу получить, будет высоко оценена.

Редактировать : Я задал похожий вопрос некоторое время назад ( здесь ), но этот вопрос был больше связан с приемом байтов и был решен с использованием кусков. В этом случае я имею дело со строками.

Edit2 : Эта библиотека является библиотекой проверки орфографии. Он работает довольно хорошо и реализует некоторые довольно продвинутые методы, такие как Soundex- и DoubleMetaPhone-алгоритмы. Пока единственной серьезной проблемой является упомянутая выше проблема с огромным текстовым файлом для испанского языка. Другие словари в порядке. Для получения дополнительной информации, пожалуйста, смотрите эту ссылку

Ответы [ 3 ]

3 голосов
/ 21 мая 2009

Поскольку вы не сказали, для чего вы используете этот файл, я предполагаю, что вы просто ищете слово по какой-то причине.

Прежде всего, вероятно, не стоит пытаться загрузить весь файл в память. Вместо этого может оказаться более продуктивным поиск в файле нужных вам данных (слов), а также, возможно, сохранение некоторой индексации информации в памяти, чтобы немного ускорить процесс.

Поскольку данные, которые вы пытаетесь найти, представляют собой просто список слов, было бы неплохо отсканировать файл и записать его в словарь, в котором изменяется первая буква слова. например, начало А в строке 0; Начало B на линии 200; C начинаются со строки 300 и т. Д. Используйте эти две части информации для заполнения своего словаря; буква - это ключ, а номер строки - это значение. По сути, словарь становится высокоуровневым индексом в файле списка слов. Этот словарь тоже очень маленький.

Затем, когда вы начинаете искать слово, используйте первую букву слова для поиска в словаре. Это даст вам номер строки, в которой слова, начинающиеся с этой буквы, находятся в файле. Вооружившись номером строки (повторно), откройте файл и перейдите прямо к этой строке в файле слова, переместив указатель потока на целевую строку. Затем найдите целевое слово оттуда. Либо ищите последовательно, строку за раз (не рекомендуется, это будет довольно медленно, но будет легче кодировать). Или ищите слово, используя бинарную отбивную (намного быстрее, но сложнее кодировать). Хотя для последнего вам также необходимо знать, где слова, начинающиеся с целевой буквы, останавливаются в файле, так как вы будете искать в разделе файла. Я также рекомендую вам выполнить поиск слов в файле, а не загружать все эти слова в память, в противном случае вы можете вернуться к тому, с чего начинаете с ошибками OOM.

Если вы ни в чем не уверены, оставьте здесь комментарий, и я сделаю все возможное, чтобы ответить на него.

Удачи

2 голосов
/ 21 мая 2009

Я бы сказал, что проблемная строка такая:

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

ГХ не может продолжать создание временных объектов за этой простой линией. «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 иногда бывает болезненным.

2 голосов
/ 21 мая 2009

Кажется, что вам просто не хватает памяти, чтобы сохранить весь текст из всех файлов в памяти одновременно. Возможно, вам потребуется разработать стратегию, которая кэширует ограниченное подмножество файлов и достаточно умна, чтобы вернуться к файлу, когда что-то запрашивается, но его нет в кэше.

Если весь смысл упражнения в том, что вам не нужно возвращаться к файлам (например, создавать какой-то индекс), вы также можете попытаться стать «умным» и придумать альтернативное представление. для текста в памяти, который использует очень сжимаемую природу большинства западных языков.

...