## 2.4 Object size

You can find out how much memory an object takes with lobstr::obj_size()5:

obj_size(letters)
#> 1,712 B
obj_size(ggplot2::diamonds)
#> 3,456,344 B

Since the elements of lists are references to values, the size of a list might be much smaller than you expect:

x <- runif(1e6)
obj_size(x)
#> 8,000,048 B

y <- list(x, x, x)
obj_size(y)
#> 8,000,128 B

y is only 80 bytes6 bigger than x. That’s the size of an empty list with three elements:

obj_size(list(NULL, NULL, NULL))
#> 80 B

Similarly, because R uses a global string pool character vectors take up less memory than you might expect: repeating a string 100 times does not make it take up 100 times as much memory.

banana <- "bananas bananas bananas"
obj_size(banana)
#> 136 B
obj_size(rep(banana, 100))
#> 928 B

References also make it challenging to think about the size of individual objects. obj_size(x) + obj_size(y) will only equal obj_size(x, y) if there are no shared values. Here, the combined size of x and y is the same as the size of y:

obj_size(x, y)
#> 8,000,128 B

Finally, R 3.5.0 and later versions have a feature that might lead to surprises: ALTREP, short for alternative representation. This allows R to represent certain types of vectors very compactly. The place you are most likely to see this is with : because instead of storing every single number in the sequence, R just stores the first and last number. This means that every sequence, no matter how large, is the same size:

obj_size(1:3)
#> 680 B
obj_size(1:1e3)
#> 680 B
obj_size(1:1e6)
#> 680 B
obj_size(1:1e9)
#> 680 B

### 2.4.1 Exercises

1. In the following example, why are object.size(y) and obj_size(y) so radically different? Consult the documentation of object.size().

y <- rep(list(runif(1e4)), 100)

object.size(y)
#> 8005648 bytes
obj_size(y)
#> 80,896 B
2. Take the following list. Why is its size somewhat misleading?

funs <- list(mean, sd, var)
obj_size(funs)
#> 17,608 B
3. Predict the output of the following code:

a <- runif(1e6)
obj_size(a)

b <- list(a, a)
obj_size(b)
obj_size(a, b)

b[[1]][[1]] <- 10
obj_size(b)
obj_size(a, b)

b[[2]][[1]] <- 10
obj_size(b)
obj_size(a, b)

1. Beware of the utils::object.size() function. It does not correctly account for shared references and will return sizes that are too large.↩︎

2. If you’re running 32-bit R, you’ll see slightly different sizes.↩︎