ここで何が起こっているのかを理解するには、R のオブジェクトに関連するメモリ オーバーヘッドについて少し知っておく必要があります。データのないオブジェクトであっても、すべてのオブジェクトには 40 バイトのデータが関連付けられています。
x0 <- numeric()
object.size(x0)
# 40 bytes
このメモリは、オブジェクトのタイプ ( によって返されるtypeof()
) と、メモリ管理に必要なその他のメタデータを格納するために使用されます。
このオーバーヘッドを無視すると、ベクトルのメモリ使用量はベクトルの長さに比例すると考えるかもしれません。いくつかのプロットでそれを確認しましょう。
sizes <- sapply(0:50, function(n) object.size(seq_len(n)))
plot(c(0, 50), c(0, max(sizes)), xlab = "Length", ylab = "Bytes",
type = "n")
abline(h = 40, col = "grey80")
abline(h = 40 + 128, col = "grey80")
abline(a = 40, b = 4, col = "grey90", lwd = 4)
lines(sizes, type = "s")
メモリ使用量はベクトルの長さにほぼ比例しているように見えますが、168 バイトで大きな不連続性があり、数ステップごとに小さな不連続性があります。大きな不連続性は、R がベクトル用の 2 つのストレージ プールを持っているためです。R によって管理される小さなベクトルと、OS によって管理される大きなベクトルです (大量の少量のメモリを割り当てるとコストがかかるため、これはパフォーマンスの最適化です)。小さなベクトルの長さは 8、16、32、48、64、または 128 バイトのみです。これは、40 バイトのオーバーヘッドを取り除くと、まさに次のようになります。
sizes - 40
# [1] 0 8 8 16 16 32 32 32 32 48 48 48 48 64 64 64 64 128 128 128 128
# [22] 128 128 128 128 128 128 128 128 128 128 128 128 136 136 144 144 152 152 160 160 168
# [43] 168 176 176 184 184 192 192 200 200
64 から 128 へのステップにより大きなステップが発生し、大きなベクトル プールに到達すると、ベクトルは 8 バイトのチャンクで割り当てられます (メモリは特定のサイズの単位で取得され、R は半分のメモリを要求できません)。単位):
# diff(sizes)
# [1] 8 0 8 0 16 0 0 0 16 0 0 0 16 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0
# [29] 0 0 0 0 8 0 8 0 8 0 8 0 8 0 8 0 8 0 8 0 8 0
では、この動作は行列で見られるものとどのように対応しているのでしょうか? まず、行列に関連するオーバーヘッドを確認する必要があります。
xv <- numeric()
xm <- matrix(xv)
object.size(xm)
# 200 bytes
object.size(xm) - object.size(xv)
# 160 bytes
そのため、行列には、ベクトルに比べて 160 バイトの余分なストレージが必要です。なぜ160バイト?これは、行列にdim
2 つの整数を含む属性があり、属性がpairlist
(古いバージョンのlist()
) に格納されているためです。
object.size(pairlist(dims = c(1L, 1L)))
# 160 bytes
ベクトルの代わりに行列を使用して前のプロットを再描画し、y 軸のすべての定数を 160 増やすと、不連続性が小さなベクトル プールから大きなベクトル プールへのジャンプに正確に対応することがわかります。
msizes <- sapply(0:50, function(n) object.size(as.matrix(seq_len(n))))
plot(c(0, 50), c(160, max(msizes)), xlab = "Length", ylab = "Bytes",
type = "n")
abline(h = 40 + 160, col = "grey80")
abline(h = 40 + 160 + 128, col = "grey80")
abline(a = 40 + 160, b = 4, col = "grey90", lwd = 4)
lines(msizes, type = "s")