Профилирование памяти меняет использование памяти (в лучшую сторону)
Это на самом деле следующий вопрос по этому вопросу. Мне удалось заставить профилирование работать, и проблема действительно кажется ленивой.
Я использую структуру данных 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
профиль показывает больше всего памяти связано с String
тип и библиотека HaXML Posn
тип. Я повторю свое предложение искать ByteString
или же Text
основанная на XML библиотека, которая является более ресурсоемкой (xml-enumerator?).