Ленивый IO - строка не мусор? - PullRequest
3 голосов
/ 20 июля 2011

В настоящее время я пытаюсь прочитать содержимое файла 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 Ответ

2 голосов
/ 21 июля 2011

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

Первый шаг - определить, какие типы потребляют больше всего памяти.Вы можете увидеть множество примеров профилирования кучи здесь на 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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...