Aby zrozumieć, co się tu dzieje, trzeba wiedzieć trochę o napowietrznej pamięci związanej z obiektami w R. każdy obiekt, nawet obiekt bez danych, ma 40 bajtów dane z nim związane:
x0 <- numeric()
object.size(x0)
# 40 bytes
pamięć ta jest używana do przechowywania typ obiektu (jak zwrócony przez typeof()
) i inne metadane potrzebne do zarządzania pamięcią.
Po zignorowaniu tego narzutu można się spodziewać, że użycie pamięci wektora jest proporcjonalne do długości wektora. Zobaczmy, że obecnie z kilku działek:
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")
Wygląda na to zużycie pamięci jest w przybliżeniu proporcjonalna do długości wektora, ale istnieje duża przerwa na 168 bajtów i małych nieciągłości każdy kilka kroków. Duża nieciągłość polega na tym, że R ma dwie pule pamięci dla wektorów: małe wektory zarządzane przez R i duże wektory zarządzane przez system operacyjny (jest to optymalizacja wydajności, ponieważ przydzielanie dużej ilości niewielkiej ilości pamięci jest kosztowne). Małe wektory mogą być tylko 8, 16, 32, 48, 64 lub 128 bajtów, który raz usuwamy napowietrznej 40 bajtów, jest dokładnie to, co widzimy:
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
Krok od 64 do 128 powoduje, że duża krok, potem kiedy już przeszedł do wielkiego basenu wektorowe, wektory są przydzielane w kawałki (8 bajtów pamięci jest w jednostkach o określonej wielkości, a R nie można prosić o pół jednostki):
# 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
Więc w jaki sposób to zachowanie odpowiada temu, co widzisz za pomocą macierzy? Cóż, najpierw musimy spojrzeć na narzutu związanego z matrycy:
xv <- numeric()
xm <- matrix(xv)
object.size(xm)
# 200 bytes
object.size(xm) - object.size(xv)
# 160 bytes
Więc matryca potrzebuje dodatkowe 160 bajtów pamięci w porównaniu do wektora. Dlaczego 160 bajtów?To dlatego, że matryca posiada atrybut dim
zawierający dwie liczby całkowite, a cechy są przechowywane w pairlist
(starszej wersji list()
):
object.size(pairlist(dims = c(1L, 1L)))
# 160 bytes
Jeśli ponownie wyciągnąć poprzedniego wykresu przy użyciu macierzy, zamiast wektorów i zwiększyć Wszystkie stałe na osi y 160, można zobaczyć nieciągłość odpowiada dokładnie skoku z małym basenem wektora do dużego basenu vector:
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 nie jest związane z macierzami (które są wektorami w R). Spójrz na 'rozmiary <- rep (NA_integer_, 100); dla (i w 1: 100) rozmiarach [i] <- object.size (rep (1, i)); działka (rozmiary) '. – Roland
Spójrz na znak 'm <- matrix ('a', 2, i)' i integer 'm <- matrix (1L, 2, i)' i 'm <- matrix (TRUE, 2, i)' - lub co bardziej interesujące, co sugerowała @Roland (dla postaci, liczb całkowitych i wektorów logicznych). – mnel
@ SimonO101 Hadley wyjaśnił to na czacie. Mam nadzieję, że znajdzie czas, aby napisać właściwą odpowiedź. Np. Przeczytaj [tę sekcję w R-exts] (http://cran.r-project.org/doc/manuals/R-exts.html#Profiling-R-code-for-memory-use). – Roland