Um zu verstehen, was hier los ist, müssen Sie ein wenig über den Speicher-Overhead mit Objekten in R. Jedes Objekt, auch ein Objekt ohne Daten zugeordnet wissen, hat 40 Byte Daten zugeordnet:
x0 <- numeric()
object.size(x0)
# 40 bytes
Dieser Speicher, die Art des Objekts zu speichern, verwendet wird (wie durch typeof()
zurückgegeben) und andere Metadaten für die Speicherverwaltung benötigt.
Nachdem Sie diesen Overhead ignoriert haben, können Sie erwarten, dass die Speichernutzung eines Vektors proportional zur Länge des Vektors ist. Lassen Sie uns prüfen, ob aus mit ein paar Stellplätze:
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")
Es ist wie die Speichernutzung aussieht, ist in etwa proportional zur Länge des Vektors, aber es ist eine große Diskontinuität bei 168 Bytes und kleine Diskontinuitäten jeder wenige Schritte. Die große Diskontinuität liegt darin, dass R zwei Speicherpools für Vektoren hat: kleine Vektoren, die von R verwaltet werden, und große Vektoren, die vom Betriebssystem verwaltet werden (Dies ist eine Leistungsoptimierung, da die Zuweisung großer Mengen an Speicher teuer ist). Kleine Vektoren nur 8 sein können, 16, 32, 48, 64 oder 128 Bytes lang ist, das, sobald wir das 40-Byte-Overhead entfernen, ist genau das, was wir sehen:
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
Der Schritt von 64 bis 128 bewirkt, dass die großen Schritt, dann, wenn wir in den großen Vektor-Pool gekreuzt haben, Vektoren wird in Blöcken von 8 Byte zugewiesen (Speicher kommt in Einheiten von einer bestimmten Größe, und R kann für eine halbe Einheit nicht fragen):
# 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
Also, wie verhält sich dieses Verhalten zu dem, was Sie mit Matrizen sehen? Nun, zuerst müssen wir den Overhead mit einer Matrix assoziiert suchen:
xv <- numeric()
xm <- matrix(xv)
object.size(xm)
# 200 bytes
object.size(xm) - object.size(xv)
# 160 bytes
So eine Matrix ein zusätzlichen 160 Byte Speicherplatz im Vergleich zu einem Vektor benötigt. Warum 160 Bytes?Es ist, weil eine Matrix, die ein dim
Attribut mit zwei ganzen Zahlen hat und Attribute in einem pairlist
(eine ältere Version von list()
) gespeichert sind:
object.size(pairlist(dims = c(1L, 1L)))
# 160 bytes
Wenn wir die vorherige Handlung wieder ziehen Matrizen anstelle von Vektoren und Erhöhung
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")
Th: alle Konstanten auf der y-Achse um 160, können Sie die Diskontinuität entspricht genau den Sprung vom kleinen Vektor Pool zum großen Vektor-Pool sehen is ist nicht verwandt mit Matrizen (die in R sowieso Vektoren sind). Sehen Sie sich 'sizes
Roland
Betrachten Sie das Zeichen 'm <- Matrix ('a', 2, i)' und die ganze Zahl 'm <- Matrix (1L, 2, i)' und 'm <- Matrix (TRUE, 2, i)' - oder interessanterweise was @Roland vorgeschlagen hat (für Zeichen, Integer und logische Vektoren). – mnel
@ SimonO101 Hadley erklärte es im Chat. Ich hoffe, er findet die Zeit, eine richtige Antwort zu schreiben. ZB lesen Sie [diesen Abschnitt in R-Exts] (http://cran.r-project.org/doc/manuals/R-exts.html#Profiling-R-code-for-memory-use). – Roland