Ваш вызов last
форсирует список, jrs
. Чтобы понять это, он должен пройти через все файлы для создания записи для каждой записи в jrs
. Поскольку вы не оцениваете каждый элемент в jrs
(кроме последнего), эти блоки выводятся со ссылками на строку байтов, поэтому они должны оставаться в памяти.
Решение состоит в том, чтобы форсировать оценку этих громов. Поскольку мы говорим о космосе, первое, что я сделал, было на самом деле сохранить вашу информацию в меньшем формате:
type Year = Word16
type Month = Word8
type Day = Word8
data Record = Rec {-# UNPACK #-} !Year {-# UNPACK #-} !Month {-# UNPACK #-} !Day
deriving (Eq, Ord, Show, Read)
Это уменьшает эту уродливую 10-байтовую строку байтов (+ издержки ~ 16 байтов информации о структуре) примерно до 8 байтов.
importRecord
теперь нужно позвонить toRecord r
, чтобы получить правильный тип:
toRecord :: BS.ByteString -> Record
toRecord bs =
case BS.splitWith (== '-') bs of
(y:m:d:[]) -> Rec (rup y) (rup m) (rup d)
_ -> Rec 0 0 0
rup :: (Read a) => BS.ByteString -> a
rup = read . BS.unpack
Нам потребуется выполнить оценку данных при преобразовании из ByteString
в Record
, поэтому давайте используем пакет параллельный и определяем экземпляр NFData из DeepSeq .
instance NFData Record where
rnf (Rec y m d) = y `seq` m `seq` d `seq` ()
Теперь мы готовы к работе, я изменил main для использования evalList
, таким образом форсируя весь список перед вашей функцией, которая хочет последнюю:
main = do
jrs <- importRecords "./tabLines"
let jrs' = using jrs (evalList rdeepseq)
loopInput jrs'
И мы можем видеть, что профиль кучи выглядит красиво (и top
согласен, программа использует очень мало памяти).
Извините за этот другой вводящий в заблуждение неправильный ответ - я подсел на тот факт, что пошаговая обработка исправляет это, и не осознавал, что на самом деле торчали громоотводы. Несмотря на то, что я поддерживаю эту суть, вы должны постепенно обрабатывать эту информацию, делая весь этот ответ спорным.
К вашему сведению, огромная строка байтов не отображалась в тех предыдущих профилях кучи, которые я опубликовал, поскольку внешние выделения (включая ByteString
) не отслеживаются профилировщиком кучи.