Профилирование памяти меняет использование памяти (в лучшую сторону)

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

Я использую структуру данных 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 строк) вместе с тестовым файлом и файлом cabal, чтобы вы могли попробовать его самостоятельно: Ссылка

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

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

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

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

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

Спасибо, что указал мне правильное направление. Как выяснилось, вы можете сказать 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 ответ

Решение

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

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

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

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

Hy профиль

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

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