How is memory for mutable variables managed?

So, in Haskell we have a bunch of different ways to have mutable variables.

  • There are «mutable references» of, as far as I know, three different flavours — IORef, MVar and TVar.
  • There are mutable arrays built into GHC, along with fancy array libraries like vector, massiv and so on.
  • There are foreign pointers that we can make point to an allocated area of memory, say with alloca.

As I understand, all three eventually refer to GHC. With the foreign pointers, I reckon they are fully low level — I can write one value into this memory, then another, and it will overwrite the first one and be put into the same location in physical RAM. So, it has 0 «management overhead». Is this right?

How do the other two types of mutable storage work? How much «management overhead» do they have?

For example, suppose I have a mutable MVar of type [Word8]. It seems hard to make sure that all the different lists I can put in there are located in the same area of memory — I guess what is actually stored is merely a reference to one or another list, and the lists themselves are managed by the garbage collector. Is this right?

What if I put an unboxed product or variant into an MVar, or a value of a Storable type — how will it be managed?

How do I research this topic — do I need to go read GHC’s source code?

1 Like

Yes, that is right.

Impossible, MVar and other mutable variable/reference types can only hold lifted (boxed) values.

The only way to store unboxed values in mutable memory is to use unboxed array.

Storable is ignored by MVar/IORef/STRef. It is stored as a pointer like any other lifted type.

4 Likes

Would it make sense to write a loop that modifies the same value a large number of times and then use a memory profiler to see how much memory it allocates?

1 Like