-
Notifications
You must be signed in to change notification settings - Fork 27
/
size.R
134 lines (123 loc) · 3.74 KB
/
size.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#' Calculate the size of an object.
#'
#' `obj_size()` computes the size of an object or set of objects;
#' `obj_sizes()` breaks down the individual contribution of multiple objects
#' to the total size.
#'
#' @section Compared to `object.size()`:
#' Compared to [object.size()], `obj_size()`:
#'
#' * Accounts for all types of shared values, not just strings in
#' the global string pool.
#'
#' * Includes the size of environments (up to `env`)
#'
#' * Accurately measures the size of ALTREP objects.
#'
#' @section Environments:
#' `obj_size()` attempts to take into account the size of the
#' environments associated with an object. This is particularly important
#' for closures and formulas, since otherwise you may not realise that you've
#' accidentally captured a large object. However, it's easy to over count:
#' you don't want to include the size of every object in every environment
#' leading back to the [emptyenv()]. `obj_size()` takes
#' a heuristic approach: it never counts the size of the global environment,
#' the base environment, the empty environment, or any namespace.
#'
#' Additionally, the `env` argument allows you to specify another
#' environment at which to stop. This defaults to the environment from which
#' `obj_size()` is called to prevent double-counting of objects created
#' elsewhere.
#'
#' @export
#' @param ... Set of objects to compute size.
#' @param env Environment in which to terminate search. This defaults to the
#' current environment so that you don't include the size of objects that
#' are already stored elsewhere.
#'
#' Regardless of the value here, `obj_size()` never looks past the
#' global or base environments.
#'
#' @return An estimate of the size of the object, in bytes.
#' @examples
#' # obj_size correctly accounts for shared references
#' x <- runif(1e4)
#' obj_size(x)
#'
#' z <- list(a = x, b = x, c = x)
#' obj_size(z)
#'
#' # this means that object size is not transitive
#' obj_size(x)
#' obj_size(z)
#' obj_size(x, z)
#'
#' # use obj_size() to see the unique contribution of each component
#' obj_sizes(x, z)
#' obj_sizes(z, x)
#' obj_sizes(!!!z)
#'
#' # obj_size() also includes the size of environments
#' f <- function() {
#' x <- 1:1e4
#' a ~ b
#' }
#' obj_size(f())
#'
#' #' # In R 3.5 and greater, `:` creates a special "ALTREP" object that only
#' # stores the first and last elements. This will make some vectors much
#' # smaller than you'd otherwise expect
#' obj_size(1:1e6)
obj_size <- function(..., env = parent.frame()) {
dots <- list2(...)
size <- obj_size_(dots, env, size_node(), size_vector())
new_bytes(size)
}
#' @rdname obj_size
#' @export
obj_sizes <- function(..., env = parent.frame()) {
dots <- list2(...)
size <- obj_csize_(dots, env, size_node(), size_vector())
names(size) <- names(dots)
new_bytes(size)
}
size_node <- function(x) as.vector(utils::object.size(quote(expr = )))
size_vector <- function(x) as.vector(utils::object.size(logical()))
new_bytes <- function(x) {
structure(x, class = "lobstr_bytes")
}
#' @export
format.lobstr_bytes <- function(x, ...) {
prettyunits::pretty_bytes(unclass(x))
}
#' @export
print.lobstr_bytes <- function(x, ...) {
fx <- format(x)
if (length(x) == 1) {
cat_line(fx)
} else {
if (!is.null(names(x))) {
cat_line(format(names(x)), ": ", fx)
} else {
cat_line("* ", fx)
}
}
invisible(x)
}
#' @export
c.lobstr_bytes <- function(...) {
new_bytes(NextMethod())
}
#' @export
`[.lobstr_bytes` <- function(...) {
new_bytes(NextMethod())
}
# Helpers for interactive exploration -------------------------------------
comp <- function(x) {
base <- utils::object.size(x)
lobstr <- obj_size(x)
c(base = base, lobstr = lobstr, diff = base - lobstr)
}
insp <- function(x) {
eval(quote(.Internal(inspect(x))))
}