Skip to content

Instantly share code, notes, and snippets.

@hasufell
Last active May 12, 2024 11:43
Show Gist options
  • Save hasufell/61ca8ef438cc912e7446bcc7b1f25028 to your computer and use it in GitHub Desktop.
Save hasufell/61ca8ef438cc912e7446bcc7b1f25028 to your computer and use it in GitHub Desktop.
Haskell String types memory overheads

Memory overheads

These calculations are the total words required modulo the payload.

List

data [] a = [] | a : (List a)
  • List constructor closure: 3 words
    • header: 1 word
    • Char closure ptr: 1 word
    • List closure ptr: 1 word
  • Empty list constructor header: 1 word
  • Char closure:
    • header: 1 word
    • paylod

=> 4 words per char + 1 word for empty list

Text

data ByteArray = ByteArray ByteArray#

data Text = Text
    {-# UNPACK #-} !ByteArray
    {-# UNPACK #-} !Int       -- offset
    {-# UNPACK #-} !Int       -- length
  • Text constructor closure: 7 words
    • header: 1 word
    • offset Int field: 1 word
    • length Int field: 1 word
    • ByteArray constructor closure: 4 words
      • header: 1 word
      • ByteArray# closure ptr: 1 word
      • ByteArray# primitive: 2 words
        • header: 1 word
        • size: 1 words
        • payload

=> 7 words

Lazy Text

data ByteArray = ByteArray ByteArray#

data Text = Text
    {-# UNPACK #-} !ByteArray
    {-# UNPACK #-} !Int       -- offset
    {-# UNPACK #-} !Int       -- length

data Text = Empty
          | Chunk {-# UNPACK #-} !T.Text Text
  • Chunk constructor closure: 8 words
    • header: 1 word
    • strict Text: 7 words
    • Lazy Text closure ptr: 1 word
  • Empty Text constructor header: 1 word

=> 9 words per chunk + 1 word for Empty

ShortText

newtype ShortText = ShortText ShortByteString
  • ShortText newtype: 4 words
    • ShortByteString newtype: 4 words
      • ByteArray closure: 4 words
        • header: 1 word
        • ByteArray constructor closure: 4 words
          • header: 1 word
          • ByteArray# closure ptr: 1 word
          • ByteArray# primitive: 2 words
            • header: 1 word
            • size: 1 words
            • payload

=> 4 words

ByteString

data ForeignPtr a = ForeignPtr Addr# ForeignPtrContents

data ForeignPtrContents
  = PlainForeignPtr !(IORef Finalizers)
  | FinalPtr
  | MallocPtr (MutableByteArray# RealWorld) !(IORef Finalizers)
  | PlainPtr (MutableByteArray# RealWorld)

-- | ByteString API uses PlainPtr
data ByteString = BS {-# UNPACK #-} !(ForeignPtr Word8) -- payload
                     {-# UNPACK #-} !Int                -- length
  • BS constructor closure: 5 words
    • header: 1 word
    • ForeignPtr constructor closure: 4 word
      • header: 1 word
      • Addr# closure ptr: 1 word
        • Addr# primitive: 1 word
      • ForeignPtrContents closure ptr: 1 word
  • ForeignPtrContents closure: 4 words
    • header: 1 word
    • PlainPtr field ptr : 1 word
      • MutableByteArray# primitive: 2 words
        • header: 1 word
        • size: 1 words
        • payload
  • length Int field: 1 word

=> 10 words

Lazy ByteString

data ForeignPtr a = ForeignPtr Addr# ForeignPtrContents

data ForeignPtrContents
  = PlainForeignPtr !(IORef Finalizers)
  | FinalPtr
  | MallocPtr (MutableByteArray# RealWorld) !(IORef Finalizers)
  | PlainPtr (MutableByteArray# RealWorld)

-- | ByteString API uses PlainPtr
data ByteString = BS {-# UNPACK #-} !(ForeignPtr Word8) -- payload
                     {-# UNPACK #-} !Int                -- length

data ByteString = Empty
                | Chunk  {-# UNPACK #-} !S.StrictByteString ByteString
  • Chunk constructor closure: 11 words
    • header: 1 word
    • strict ByteString: 10 words
    • Lazy ByteString closure ptr: 1 word
  • Empty ByteString constructor header: 1 word

=> 12 words per chunk + 1 word for Empty

ShortByteString

data ByteArray = ByteArray ByteArray#

newtype ShortByteString = ShortByteString { unShortByteString :: ByteArray }
  • ShortByteString newtype: 4 words
    • ByteArray closure: 4 words
      • header: 1 word
      • ByteArray# closure ptr: 1 word
      • ByteArray# primitive: 2 words
        • header: 1 word
        • size: 1 words
        • payload

=> 4 words

Bytes

data ByteArray = ByteArray ByteArray#

data Bytes = Bytes
  { array :: {-# UNPACK #-} !ByteArray
  , offset :: {-# UNPACK #-} !Int
  , length :: {-# UNPACK #-} !Int
  }
  • Bytes constructor closure: 6 words
    • header: 1 word
    • offset Int field: 1 word
    • length Int field: 1 word
    • ByteArray constructor closure: 4 words
      • header: 1 word
      • ByteArray# closure ptr: 1 word
      • ByteArray# primitive: 2 words
        • header: 1 word
        • size: 1 words
        • payload

=> 7 words

Chunks

data ByteArray = ByteArray ByteArray#

data Bytes = Bytes
  { array :: {-# UNPACK #-} !ByteArray
  , offset :: {-# UNPACK #-} !Int
  , length :: {-# UNPACK #-} !Int
  }

data Chunks
  = ChunksCons {-# UNPACK #-} !Bytes !Chunks
  | ChunksNil
  • Chunks constructor closure: 8 words
    • header: 1 word
    • Bytes: 7 words
    • Chunks closure ptr: 1 word
  • ChunksNil constructor header: 1 word

=> 9 words per chunk + 1 word for ChunksNil

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment