профилирование памяти меняет использование памяти (в лучшую сторону) - PullRequest
8 голосов
/ 29 июля 2011

Это на самом деле дополнительный вопрос этого вопроса.Мне удалось заставить профилирование работать, и проблема действительно кажется ленивой.

Используемая мной структура данных: Map Int (Map Int Text), где Text из Data.Text .Проблема в том, что функция, которая строит эту карту, создает огромный поток.Работая с вводимым текстом размером около 3 МБ, программам требуется более 250 МБ памяти.

Теперь для реальной цели этого вопроса:

Чтобы получить количество символов в этой структуре данныхэто использовать следующую функцию:

type TextResource = M.Map Int (M.Map Int T.Text)

totalSize :: TextResouce -> Int
totalSize = M.fold ((+) . (M.fold ((+). T.length) 0)) 0

Не красиво, но он выполняет свою работу.Я использую эту функцию в основной функции сразу после создания TextResource.Интересно то, что когда я профилирую программу, используя опцию RTS -hr или -hc, через некоторое время использование памяти уменьшается до 70 или 50 МБ, что было бы вполне нормально.

К сожалениюэто работает только при использовании параметров профилирования и функции totalSize - без них он возвращается к 250 МБ.

Я загрузил программу (<70 строк) вместе с тестовым файлом и кабальным файлом, так чтоВы можете попробовать сами: <a href="http://www.file-upload.net/download-3623479/leak.zip.html" rel="nofollow noreferrer"> Ссылка

test.xml - это сгенерированный XML-файл, который следует поместить в каталог исполняемых файлов.Для сборки достаточно cabal configure --enable-executable-profiling, а затем cabal build (если у вас установлены профилирующие версии необходимых библиотек).

Вы можете увидеть изменения при запуске программы один раз с +RTS -hc и один раз без.

Было бы здорово, если бы кто-то мог запустить программу, так как я действительно застрял здесь,Я уже пытался вставить deepseq в нескольких местах, но ничего не работает (ну, кроме использования параметров профилирования).

Редактировать:

Профилирование показывает, однако, что используется только ~ 20 МБ кучи, поэтому, как в моем комментарии, я обвиняю GHC в том, что неосвобождая столько памяти ГК, сколько вы, кажется, хотите.

Спасибо, это указало мне правильное направление.Как выяснилось, вы можете сказать GHC выполнить сборку мусора ( executeGC ), которая прекрасно работает после глубокого изучения карты.Несмотря на то, что я полагаю, что использование executeGC не рекомендуется, это, кажется, правильный инструмент для работы здесь.

Edit2: Вот как я изменил основную функцию (+ глубокий поисквозврат buildTextFile):

main = do tf <- buildTextFile "test.xml"
          performGC
          putStrLn . show . text 1 1000 $ tf
          getLine
          putStrLn . show . text 100 1000 $ tf
          return ()

1 Ответ

4 голосов
/ 30 июля 2011

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

Нет. Основываясь на профилировании кучи, я не верю, что использование пространства - это гром. Кроме того, я заменил Data.Map на строгие HashMaps и заставил карту (чтобы избежать создания больших групп) с тем же результатом.

когда я профилирую программу с помощью опции RTS -hr или -hc, через некоторое время использование памяти уменьшается до 70 или 50 МБ

Я не могу воспроизвести это. С -hr, -hy или -hc процесс сохраняет кучу 140 МБ. Однако профилирование показывает, что используется только ~ 20 МБ кучи, поэтому, как я отмечаю в своем комментарии, я обвиняю GHC в том, что он не освободил столько памяти детской комнаты GC, как вам кажется.

The -hy profile

Что касается большого использования памяти во время вычислений, приведенный выше профиль -hy показывает, что большая часть памяти связана с типом String и типом библиотеки HaXML Posn. Я повторю свое предложение о поиске библиотеки XML на основе ByteString или Text, которая более требовательна к ресурсам (xml-enumerator?).

...