2014-12-03 13 views
13
3,200,056,496 bytes allocated in the heap 

Wut? To jest mały test dla STRef:Dlaczego moja mała STRef Int wymaga przydziału gigabajtów?

bigNumber = 
    runST $ do 
     ref <- newSTRef (0 :: Int) 
     replicateM_ 100000000 $ modifySTRef' ref (+1) 
     readSTRef ref 

modifySTRef' jest rygorystyczny. STRef ma działać bezpośrednio w pamięci, więc nie widzę potrzeby wielu alokacji.

Oto pełny kod:

import Control.Monad.ST 
import Control.Monad 
import Data.STRef 

bigNumber :: Int 
bigNumber = 
    runST $ do 
     ref <- newSTRef (0 :: Int) 
     replicateM_ 100000000 $ modifySTRef' ref (+1) 
     readSTRef ref 

main :: IO() 
main = print bigNumber 

budowy do profilowania jak:

ghc -O2 -rtsopts -prof -auto-all -caf-all -fforce-recomp tryST.hs 

Run jak:

./tryST +RTS -pa -sstderr 

Highlight z tryST.prof

bigNumber Main 95 1 95.7 100.0 95.7 100.0 1357 1600000032 

RTS zgłosić:

3,200,056,496 bytes allocated in the heap 
     360,624 bytes copied during GC 
     46,040 bytes maximum residency (2 sample(s)) 
     23,592 bytes maximum slop 
      1 MB total memory in use (0 MB lost due to fragmentation) 

            Tot time (elapsed) Avg pause Max pause 
Gen 0  6102 colls,  0 par 0.03s 0.03s  0.0000s 0.0002s 
Gen 1   2 colls,  0 par 0.00s 0.00s  0.0007s 0.0013s 

INIT time 0.00s ( 0.00s elapsed) 
MUT  time 1.33s ( 1.38s elapsed) 
GC  time 0.03s ( 0.04s elapsed) 
RP  time 0.00s ( 0.00s elapsed) 
PROF time 0.00s ( 0.00s elapsed) 
EXIT time 0.00s ( 0.00s elapsed) 
Total time 1.35s ( 1.42s elapsed) 

%GC  time  1.9% (2.5% elapsed) 

Alloc rate 2,413,129,982 bytes per MUT second 

Productivity 98.1% of total user, 93.6% of total elapsed 

Ten program nie jest tak szybki jak chciałbym, ale wydajność wynosi 98%. Wspaniały. Maksymalna rezydentura 46k. Chłodny. Ale co to jest za całą alokację?

Odpowiedz

9

Typ Int jest reprezentacją liczby całkowitej. Gdy (+1) działa na zawartość obiektu , tworzony jest nowy obiekt sterty. Wewnętrznie, STRef przechowuje wskaźnik do obiektu stosu i zapisuje do niego, modyfikując wskaźnik, zamiast aktualizować pole liczby całkowitej. Jak widać, zrobienie tego 1 000 000 000 razy może spowodować powstanie dużej liczby obiektów Int, przebijających dużą ilość pamięci.

Na szczęście obiekty te nie są długotrwałe, dlatego stosunkowo niewiele bajtów jest kopiowanych przez śmieciarz. Rzeczywiście, ten program spędza tylko niewielką ilość czasu wykonując GC. Krótkotrwałe obiekty, takie jak ten, są dość powszechne w Haskell (i wielu innych językach programowania funkcjonalnego), a garbage collector jest przeznaczony do efektywnego obchodzenia się z nimi.

+0

Interesujące. Właśnie zapoznałem się z zaletami unboxingu w kontekście rozpakowywanych wektorów. Czy istnieje sposób na unboxed Int w STRef? –

+1

@MichaelFox [This] (https://hackage.haskell.org/package/ArrayRef-0.1.3.1/docs/Data-Ref-Unboxed.html) jest jednym z możliwych rozwiązań. Nie wiem jednak, czy istnieje standaryzowane rozwiązanie. Przypuszczam, że mógłbyś użyć rozpakowanego wektora o długości 1, gdybyś był zdesperowany. – sabauma

+0

W praktyce nie jest to tak ważne. Nie umieszczasz często używanych wartości w rodzaju Ref, przekazujesz je. Jeśli twój kod i typ wartości na to pozwalają, wartość zostanie rozpakowana. – Carl

Powiązane problemy