Haskellにデータタイプの値を格納するために必要な実際のメモリ容量を見つけるにはどうすればよいですか(主にGHCを使用)。実行時に(GHCiなどで)評価することは可能ですか、それともそのコンポーネントから複合データ型のメモリ要件を見積もることは可能ですか?
一般に、タイプa
およびb
のメモリ要件がわかっている場合、次のような代数的データタイプのメモリオーバーヘッドはどのくらいですか。
data Uno = Uno a
data Due = Due a b
たとえば、これらの値が占めるメモリ内のバイト数は?
1 :: Int8
1 :: Integer
2^100 :: Integer
\x -> x + 1
(1 :: Int8, 2 :: Int8)
[1] :: [Int8]
Just (1 :: Int8)
Nothing
ガベージコレクションの遅延により、実際のメモリ割り当てが高くなることを理解しています。遅延評価のために大きく異なる場合があります(サンクサイズは値のサイズとは関係ありません)。問題は、データ型が与えられた場合、完全に評価されたときにその値がどれだけのメモリを消費するかということです。
GHCiにはメモリ統計を表示する:set +s
オプションがあることがわかりましたが、単一の値のメモリフットプリントを推定する方法は明確ではありません。
(以下はGHCに適用され、他のコンパイラは異なる格納規則を使用する場合があります)
経験則:コンストラクターはヘッダーに1ワード、各フィールドに1ワードかかります。例外:フィールドのないコンストラクター(Nothing
やTrue
など)はスペースを取りません。GHCがこれらのコンストラクターの単一のインスタンスを作成し、すべての用途で共有するためです。
Wordは、32ビットマシンでは4バイト、64ビットマシンでは8バイトです。
したがって、たとえば.
data Uno = Uno a
data Due = Due a b
Uno
は2ワード、Due
は3ワードかかります。
Int
タイプは次のように定義されます
data Int = I# Int#
現在、Int#
は1ワードを使用するため、Int
は合計2ワードを使用します。ほとんどのボックス化されていない型は1つのWordを受け取りますが、例外はInt64#
、Word64#
、およびDouble#
(32ビットマシン上)で、2をとります。GHCは実際には型の小さな値のキャッシュを持っていますInt
およびChar
なので、多くの場合、これらはヒープ領域をまったく消費しません。 String
s> 255を使用しない限り、Char
にはリストセル用のスペースのみが必要です。
Int8
の表現はInt
と同じです。 Integer
は次のように定義されています:
data Integer
= S# Int# -- small integers
| J# Int# ByteArray# -- large integers
したがって、小さいInteger
(S#
)は2ワードを使用しますが、大きい整数はその値に応じて可変量のスペースを使用します。 ByteArray#
には、2ワード(ヘッダー+サイズ)と配列自体のスペースが必要です。
newtype
で定義されたコンストラクターは無料であることに注意してください。 newtype
は純粋にコンパイル時のアイデアであり、実行時にスペースを取らず、命令のコストもかかりません。
詳細は GHC解説のヒープオブジェクトのレイアウト を参照してください。
Ghc-datasizeパッケージは、GHCオブジェクトのサイズを計算するための recursiveSize 関数を提供します。しかしながら...
ガベージコレクターはヒープのウォークを困難にするため、サイズが計算される前にガベージコレクションが実行されます。
...そのため、これを頻繁に呼び出すのは現実的ではありません!
データ型のGHCのメモリ表現を見つける方法は? および Haskellで型のサイズを確認するにはどうすればよいですか? も参照してください。