2013-08-16 16 views
6

Mam obliczenia wewnątrz ST, który przydziela pamięć za pomocą Data.Vector.Unboxed.Mutable. Wektor nigdy nie jest czytany ani zapisywany, ani też żadne odniesienie nie zostało do niego zachowane poza runST (zgodnie z moją najlepszą wiedzą). Problem polega na tym, że kiedy wielokrotnie wykonuję obliczenia ST, czasami wydaje mi się, że przechowuję pamięć dla wektora.Haskell: Wyciek pamięci ze ST/GC nie zbiera?

statystyki Przeznaczenie:

5,435,386,768 bytes allocated in the heap 
    5,313,968 bytes copied during GC 
    134,364,780 bytes maximum residency (14 sample(s)) 
    3,160,340 bytes maximum slop 
      518 MB total memory in use (0 MB lost due to fragmentation) 

Tutaj nazywam runST 20x z różnymi wartościami dla moich obliczeń i wektorem 128MB (ponownie - nieużywany, nie zwrócone lub odwoływać poza ST). Maksymalna rezydencja wygląda dobrze, w zasadzie tylko mój wektor plus kilka MB innych rzeczy. Ale całkowite użycie pamięci wskazuje, że mam cztery aktywne obrazy w tym samym czasie. To idealnie pasuje do wielkości wektora, dla 256 MB otrzymujemy 1030 MB zgodnie z oczekiwaniami.

W wektorze 1GB zabrakło pamięci (4x1GB + obciążenie> 32-bitowe). Nie rozumiem, dlaczego RTS zachowuje pozornie nieużywaną, nieprzywiązaną pamięć wokół, zamiast po prostu ją GC'ing, przynajmniej w miejscu, w którym alokacja w przeciwnym razie by zawiodła.

Biegając z + RTS -S ujawnia, co następuje:

Alloc Copied  Live GC GC  TOT  TOT Page Flts 
    bytes  bytes  bytes user elap user elap 
134940616  13056 134353540 0.00 0.00 0.09 0.19 0 0 (Gen: 1) 
    583416  6756 134347504 0.00 0.00 0.09 0.19 0 0 (Gen: 0) 
    518020  17396 134349640 0.00 0.00 0.09 0.19 0 0 (Gen: 1) 
    521104  13032 134359988 0.00 0.00 0.09 0.19 0 0 (Gen: 0) 
    520972  1344 134360752 0.00 0.00 0.09 0.19 0 0 (Gen: 0) 
    521100  828 134360684 0.00 0.00 0.10 0.19 0 0 (Gen: 0) 
    520812  592 134360528 0.00 0.00 0.10 0.19 0 0 (Gen: 0) 
    520936  1344 134361324 0.00 0.00 0.10 0.19 0 0 (Gen: 0) 
    520788  1480 134361476 0.00 0.00 0.10 0.20 0 0 (Gen: 0) 
134438548  5964 268673908 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    586300  3084 268667168 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    517840  952 268666340 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    520920  544 268666164 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    520780  428 268666048 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    520820  2908 268668524 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    520732  1788 268668636 0.00 0.00 0.19 0.39 0 0 (Gen: 0) 
    521076  564 268668492 0.00 0.00 0.19 0.39 0 0 (Gen: 0) 
    520532  712 268668640 0.00 0.00 0.19 0.39 0 0 (Gen: 0) 
    520764  956 268668884 0.00 0.00 0.19 0.39 0 0 (Gen: 0) 
    520816  420 268668348 0.00 0.00 0.20 0.39 0 0 (Gen: 0) 
    520948  1332 268669260 0.00 0.00 0.20 0.39 0 0 (Gen: 0) 
    520784  616 268668544 0.00 0.00 0.20 0.39 0 0 (Gen: 0) 
    521416  836 268668764 0.00 0.00 0.20 0.39 0 0 (Gen: 0) 
    520488  1240 268669168 0.00 0.00 0.20 0.40 0 0 (Gen: 0) 
    520824  1608 268669536 0.00 0.00 0.20 0.40 0 0 (Gen: 0) 
    520688  1276 268669204 0.00 0.00 0.20 0.40 0 0 (Gen: 0) 
    520252  1332 268669260 0.00 0.00 0.20 0.40 0 0 (Gen: 0) 
    520672  1000 268668928 0.00 0.00 0.20 0.40 0 0 (Gen: 0) 
134553500  5640 402973292 0.00 0.00 0.29 0.58 0 0 (Gen: 0) 
    586776  2644 402966160 0.00 0.00 0.29 0.58 0 0 (Gen: 0) 
    518064  26784 134342772 0.00 0.00 0.29 0.58 0 0 (Gen: 1) 
    520828  3120 134343528 0.00 0.00 0.29 0.59 0 0 (Gen: 0) 
    521108  756 134342668 0.00 0.00 0.30 0.59 0 0 (Gen: 0) 

Tutaj wydaje się, mamy przekraczającej ~ 128MB 'Żywe bajty.'

Profil +RTS -hy zasadzie tylko mówi, że przeznaczyć 128MB:

http://imageshack.us/a/img69/7765/45q8.png

Próbowałem odtwarzając to zachowanie w prostszym programem, ale nawet z replikacji dokładną konfigurację z ST, czytnik zawierającej wektor, tym samym monad/struktura programu itp. prosty program testowy tego nie pokazuje. Upraszczając mój wielki program, zachowanie również zatrzymuje się w końcu podczas usuwania pozornie zupełnie niepowiązanego kodu.

Qs:

  • Am I naprawdę utrzymując ten wektor około 4 razy na 20?
  • Jeśli tak, to w jaki sposób mogę powiedzieć, że +RTS -Hy i maximum residency twierdzą, że nie jestem i co mogę zrobić, aby zatrzymać to zachowanie?
  • Jeśli nie, dlaczego Haskell nie zgłasza go i brakuje przestrzeni adresowej/pamięci i co mogę zrobić, aby zatrzymać to zachowanie?

Dzięki!

+2

Używana pamięć jest zwykle dwukrotnie większa od maksymalnej rezydentności lub więcej, w zależności od wzoru przydziału i odbioru. Tak więc całkowita wykorzystana pamięć 518 MB nie jest sama w sobie alarmująca. Spróbuj powiedzieć GHC, że na dysku jest tylko tyle pamięci, na przykład '$ ./foo + RTS -M256M', aby zmusić go do wcześniejszego pobrania. Ale "ani odniesienie zachowane do niego poza runST" może być nieprawdziwe, naprawdę można mieć przeciek. W takim przypadku trzeba by zobaczyć kod. –

+0

@DanielFischer 518MB ma rozmiar ~ 4x. Czy awaria pamięci z wektorem 1GB nie wskaże, że GHC * nie może * zebrać pamięci? + RTS -M256M kończy się niepowodzeniem z "Heap exhausted". Wektor jest tworzony, umieszczony w środowisku Reader, to wszystko. Nic więcej, nie jestem pewien, co jeszcze mogę zrobić, aby uniknąć wycieku odniesień po opuszczeniu ST/Reader. Tak jak powiedziałem, nie mogę odtworzyć tego problemu w prostszym programie. Wydaje się raczej losowy. – NBFGRTW

+0

Cóż, 4 × może się zdarzyć, biorąc pod uwagę prawy/zły schemat alokacji. Awaria poza pamięcią może wskazywać, że GHC nie wie, że powinna się teraz zbierać, ale biorąc pod uwagę, że '-M256M' powoduje, że" stos wyczerpany ", wygląda bardziej jak coś ma odniesienie do bestii. –

Odpowiedz

2

Podejrzewam, że jest to błąd w GHC i/lub RTS.

Po pierwsze, jestem przekonany, że nie ma rzeczywistego wycieku przestrzeni kosmicznej ani nic takiego.

Przyczyny:

  • Wektor nigdy nie jest używany w dowolnym miejscu. Nie czytane, niepisane, nie wymienione. Powinien zostać zebrany, gdy runST zostanie ukończony. Nawet jeśli obliczenie ST zwraca pojedynczą wartość Int, która jest natychmiast drukowana w celu jej oceny, problem z pamięcią nadal istnieje. Nie ma odniesienia do tych danych.
  • Każdy tryb profilowania, który oferuje RTS, jest zgodny z przemocą, że nigdy nie posiadam więcej niż jednej wartości pamięci przydzielonej/odniesionej do pojedynczego wektora. Każda statystyka i ładny wykres to potwierdzają.

Oto interesujący fragment. Jeśli ręcznie wymuszam GC wywołując System.Mem.performGC po każdym uruchomieniu mojej funkcji, problem znika całkowicie.

Mamy więc przypadek, w którym środowisko wykonawcze ma pamięć GB, którą (ewidentnie!) Może odzyskać GC, a nawet według własnej statystyki nie jest już w posiadaniu nikogo. Po wyczerpaniu puli pamięci środowisko wykonawcze nie zbiera się, ale zamiast tego prosi system operacyjny o więcej pamięci. Nawet jeśli to się nie powiedzie, środowisko wykonawcze nadal nie zbiera się (co w sposób ewidentny odzyskałoby GB pamięci), ale zamiast tego zdecyduje się zakończyć program z błędem braku pamięci.

Nie jestem ekspertem od Haskella, GHC lub GC. Ale to wygląda na strasznie zepsute. Zgłoszę to jako błąd.

+0

Czy kiedykolwiek zdarzyło Ci się Zgłoś to? – jberryman