3,200,056,496 bytes allocated in the heap
Wut? This is a small test for STRef:
bigNumber =
runST $ do
ref <- newSTRef (0 :: Int)
replicateM_ 100000000 $ modifySTRef' ref (+1)
readSTRef ref
modifySTRef'
is strict. STRef
is supposed to operate directly on memory so I don't see the need for lots of allocations.
Here's the full code:
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
Build for profiling like:
ghc -O2 -rtsopts -prof -auto-all -caf-all -fforce-recomp tryST.hs
Run like:
./tryST +RTS -pa -sstderr
Highlight from tryST.prof
bigNumber Main 95 1 95.7 100.0 95.7 100.0 1357 1600000032
The RTS report:
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
This program isn't as fast as I'd like but the productivity is 98%. Great. Maximum residency 46k. Cool. But what is with all that allocation?
The Int
type is a box integer representation. When (+1)
acts on the contents
of the STRef
, a new heap object is created. Internally, the STRef
holds a pointer to the heap object, and writes to that STRef
modify the pointer, rather than updating an integer field. As you can see, doing this 1,000,000,000 times can result in a large number of Int objects being created, churning through a lot of memory.
Fortunately, these objects are not long lived, which is why relatively few bytes are copied by the garbage collector. Indeed, this program is spending only a modest amount of time performing GC. Short lived objects like this are quite common in Haskell (and many other functional programming languages), and the garbage collector is designed to handle this efficiently.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With