2014-11-03 1 views
22

ВведениеКак я могу сделать освобождение памяти GHCI

Следующий код показывает, что при использовании runhaskell Haskell сборщик мусора освобождает память, когда a больше не используется. Это приводит к дампу ядра, освобождая переменную a - для целей проверки поведения - a получил nullFunPtr в качестве финализатора.

module Main where 

import Foreign.Ptr 
import Foreign.ForeignPtr 


main :: IO() 
main = do 
    a <- newForeignPtr nullFunPtr nullPtr 
    putStrLn "Hello World" 

Проблема

При работе то же самое в GHCI это не освобождает память. Как заставить ghci освобождать больше не используемые переменные?

$ ghci 
> import Foreign.Ptr 
> import Foreign.ForeignPtr 
> import System.Mem 
> a <- newForeignPtr nullFunPtr nullPtr 
> a <- return() -- rebinding variable a to show gc that I'm no longer using it 
> performGC 
> -- did not crash - GC didn't release memory 
> ^D 
Leaving GHCi. 
[1] 4396 segmentation fault (core dumped) ghci 

Память была выпущена при выходе, но это слишком поздно для меня. Я расширяю GHCi и использую его для других целей, и мне нужно освободить память раньше - по требованию или как можно быстрее, было бы действительно здорово.

Я знаю, что могу позвонить finalizeForeignPtr, но я использую foreignPtr только для целей отладки. Как я могу выслать a вообще в последнем примере?

Если у вас нет возможности сделать это с помощью ghci prompt, я также могу изменить код ghci. Может быть, я могу освободить этот a от modyfing ghci Interactive Context или DynFlags? До сих пор мне не повезло с моим reaserch.

+1

Вы уверены, что память не была выпущена? Я не думаю, что есть гарантия, что финализаторы работают быстро, когда переменная GC'd. –

+1

Скорее да, я делал подобные тесты с большими массивами и контролировал его с помощью 'ekg'. Ничего не было выпущено. – remdezx

+0

Зачем должен быть '' 'мусор, собранный после переназначения на'() '? Как может ghci знать (из-за своего рода монашон IO), он не понадобится? –

ответ

9

Трассировка через код, мы находим, что значение сохраняется в поле closure_env типа данных PersistentLinkerState, который представляет собой ClosureEnv, т.е. отображение из имени в HValue с. Соответствующая функция в Linker.hs является

extendLinkEnv :: [(Name,HValue)] -> IO() 
-- Automatically discards shadowed bindings 
extendLinkEnv new_bindings = 
    modifyPLS_ $ \pls -> 
    let new_closure_env = extendClosureEnv (closure_env pls) new_bindings 
    in return pls{ closure_env = new_closure_env } 

и хотя комментарий указывает на то, что он должен удалить слежка связывания, это не так, по крайней мере, не так, как вы хотите.

Причина в том, что, поскольку AndrewC пишет правильно: хотя обе переменные имеют одинаковое исходное кодовое имя, они отличаются от компилятора (у них есть другой Unique). Мы можем наблюдать это после добавления некоторой трассировки к вышеупомянутой функции:

*GHCiGC> a <- newForeignPtr nullFunPtr nullPtr 
extendLinkEnv [a_azp] 
*GHCiGC> a <- return() 
extendLinkEnv [a_aF0] 
*GHCiGC> performGC 
extendLinkEnv [it_aFL] 

Удаления привязок с тем же источником, именем в этой точке должны решить вашу проблему GC, но я не знаю компилятор достаточно хорошо, чтобы сказать, что иначе сломался бы. Я предлагаю вам открыть билет, надеюсь, кто-то узнает.

Беспорядок на связывание против значения

В комментариях, кажется, некоторая путаница относительно привязок и значений.Рассмотрим этот код:

> a <- return something 
> b <- return somethingelse 
> a <- return (b+b) 
> b <- return anewthing 

С текущей реализации, куча будет состоять из `

  • something
  • somethingelse
  • стуком ссылки на (+) оператора и somethingelse
  • anewthing.

Кроме того, среда интерпретатора имеет ссылки на все четыре значения кучи, поэтому ничто не может быть GC'ed.

Что remdezx справедливо ожидать, что GH сбросят ссылки на something и somethingelse. Это, в свою очередь, позволит системе времени выполнения сбора мусора собирать something (мы не предполагаем дальнейших ссылок). GHCi все еще ссылается на thunk, который, в свою очередь, ссылается на somethingelse, поэтому это будет не быть собранным мусором.

Понятно, что вопрос был очень специфичным для реализации, и вот этот ответ :-)

+2

привязка может быть затенена, но косвенно косвенно указана: 'a <- return 1; f <- return (const a); a <- return(); print $ f undefined'. –

+0

Благодарим вас за то, что вы больше подходите к этой теме! Я уже сообщал об аналогичной ошибке (https://ghc.haskell.org/trac/ghc/ticket/9765), но я сообщу еще один и отделите проблему. – remdezx

+2

@Will Ness: привязку больше нельзя ссылаться. Конечно, «ценность» может, но на нее безопасно ссылается закрытие, нет необходимости в «среде названных вещей», чтобы держаться за нее! –

Смежные вопросы