Ленивый IO - строка не мусор?

В настоящее время я пытаюсь прочитать содержимое файла XML в Map Int (Map Int String) и это работает довольно хорошо (используя HaXml). Тем не менее, меня не устраивает потребление памяти моей программой, и проблемы, похоже, связаны с сборкой мусора.

Вот код, который я использую для чтения файла XML:

type TextFile = Map Int (Map Int String)

buildTextFile :: String -> IO TextFile
buildTextFile filename = do content <- readFile filename
                            let doc = xmlParse filename content
                                con = docContent (posInNewCxt filename Nothing) doc
                            return $ buildTF con

Я думаю, что content сохраняется в памяти даже после возвращения, хотя это не обязательно (конечно, это также может быть doc или же con). Я пришел к такому выводу, потому что потребление памяти быстро увеличивается с очень большими файлами XML, хотя в результате TextFile является только одноэлементной картой одноэлементной карты (с использованием специального файла тестирования, как правило, это другое, конечно). Итак, в конце концов, у меня есть Map из Map Int String, только с одной строкой, но потребление памяти составляет до 19 МБ.

Используя строгое приложение ($!) или используя Data.Text вместо String в TextFile ничего не меняет

Итак, мой вопрос: есть ли способ сказать компилятору, что строка content (или же doc или же con) больше не нужен и что его можно собирать?

И в целом: как я могу узнать, откуда на самом деле возникает проблема, не догадываясь?

Редактировать: как предложил FUZxxl, я попытался использовать deepseq и изменил вторую строку buildTextFile вот так:

let doc = content `deepseq` xmlParse filename content

К сожалению, это ничего не изменило (или я использую это неправильно?)...

1 ответ

Решение

Не угадай, что потребляет память, узнай наверняка

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

Принудительное вычисление

Если проблема заключается в отложенной оценке (вы создаете блок в куче, который может вычислить тип документа XML и также оставляете строку в куче), тогда используйте rnf и seq:

buildTextFile :: String -> IO TextFile
buildTextFile filename = do content <- readFile filename
                            let doc = xmlParse filename content
                                con = docContent (posInNewCxt filename Nothing) doc
                                res = buildTF con
                            return $ rnf res `seq` res

Или просто используйте шаблоны взрыва (!res = buildTF con), так или иначе, что должно заставить громов и позволить GC собирать String,

Другие вопросы по тегам