Я написал библиотеку под названием amqp-worker, которая предоставляет функцию с именем worker
, которая опросает очередь сообщений (например, RabbitMQ) для сообщений, вызывая обработчик при обнаружении сообщения. Затем он возвращается к опросу.Утечка памяти в рекурсивной функции ввода-вывода - PAP
Это утечка памяти. Я профилировал его, и график говорит, что виновником является PAP
(приложение частичной функции). Где утечка в моем коде? Как я могу избежать утечек при зацикливании в IO
с forever
?
Вот некоторые важные функции. The full source is here.
Example Program. Эта утечка
main :: IO()
main = do
-- connect
conn <- Worker.connect (fromURI "amqp://guest:[email protected]:5672")
-- initialize the queues
Worker.initQueue conn queue
Worker.initQueue conn results
-- publish a message
Worker.publish conn queue (TestMessage "hello world")
-- create a worker, the program loops here
Worker.worker def conn queue onError (onMessage conn)
worker :: (FromJSON a, MonadBaseControl IO m, MonadCatch m) => WorkerOptions -> Connection -> Queue key a -> (WorkerException SomeException -> m()) -> (Message a -> m()) -> m()
worker opts conn queue onError action =
forever $ do
eres <- consumeNext (pollDelay opts) conn queue
case eres of
Error (ParseError reason bd) ->
onError (MessageParseError bd reason)
Parsed msg ->
catch
(action msg)
(onError . OtherException (body msg))
liftBase $ threadDelay (loopDelay opts)
consumeNext :: (FromJSON msg, MonadBaseControl IO m) => Microseconds -> Connection -> Queue key msg -> m (ConsumeResult msg)
consumeNext pd conn queue =
poll pd $ consume conn queue
poll :: (MonadBaseControl IO m) => Int -> m (Maybe a) -> m a
poll us action = do
ma <- action
case ma of
Just a -> return a
Nothing -> do
liftBase $ threadDelay us
poll us action
Что ваша версия ghc и как вы компилируете? – jberryman
Он установлен в lts-7.3, так что GHC 8.0.1. Я собираюсь с установкой стека --profile. Но я получаю утечку памяти с нормальной установкой стека. Использование параметров ghc по умолчанию из шаблона стека: -threaded -rtsopts -with-rtsopts = -N –
Этот пример очень далек от минимального - вы импортируете всю свою библиотеку ('Network.AMQP.Worker') в свою примерную программу. Как бы то ни было, это слишком широко. – user2407038