Я делаю различные ggplot
с на очень большом наборе данных (намного больше, чем в примерах). Я создал функцию биннинга по осям X и Y, чтобы включить построение такого большого набора данных.
В следующем примере memory.size()
записывается в начале. Затем большой набор данных моделируется как dt
. dt
s x2
наносится на график против x1
с биннингом. Построение повторяется с различными подмножествами dt
. Размер построенного объекта проверяется object.size()
и сохраняется. После создания объектов построения выполняется rm(dt)
, за которым следует двойное gc()
. В этот момент memory.size()
записывается снова. В конце, memory.size()
в конце сравнивается с таковым в начале и печатается.
Ввиду небольшого размера построенного объекта ожидается, что memory.size()
в конце должен быть аналогичен тому, который был в начале. Но нет. memory.size()
больше не отключается, пока я не перезапущу новый сеанс R .
Воспроизводимый пример
library(data.table)
library(ggplot2)
library(magrittr)
# The binning function
# x = column name for x-axis (character)
# y = column name for y-axis (character)
# xNItv = Number of bin for x-axis
# yNItv = Number of bin for y-axis
# Value: A binned data.table
tab_by_bin_idxy <- function(dt, x, y, xNItv, yNItv) {
#Binning
xBreaks = dt[, seq(min(get(x), na.rm = T), max(get(x), na.rm = T), length.out = xNItv + 1)]
yBreaks = dt[, seq(min(get(y), na.rm = T), max(get(y), na.rm = T), length.out = yNItv + 1)]
xbinCode = dt[, .bincode(get(x), breaks = xBreaks, include.lowest = T)]
xbinMid = sapply(seq(xNItv), function(i) {return(mean(xBreaks[c(i, i+1)]))})[xbinCode]
ybinCode = dt[, .bincode(get(y), breaks = yBreaks, include.lowest = T)]
ybinMid = sapply(seq(yNItv), function(i) {return(mean(yBreaks[c(i, i+1)]))})[ybinCode]
#Creating table
tab_match = CJ(xbinCode = seq(xNItv), ybinCode = seq(yNItv))
tab_plot = data.table(xbinCode, xbinMid, ybinCode, ybinMid)[
tab_match, .(xbinMid = xbinMid[1], ybinMid = ybinMid[1], N = .N), keyby = .EACHI, on = c("xbinCode", "ybinCode")
]
#Returning table
return(tab_plot)
}
before.mem.size <- memory.size()
# Simulation of dataset
nrow <- 6e5
ncol <- 60
dt <- do.call(data.table, lapply(seq(ncol), function(i) {return(runif(nrow))}) %>% set_names(paste0("x", seq(ncol))))
# Graph plotting
dummyEnv <- new.env()
with(dummyEnv, {
fcn <- function(tab) {
binned.dt <- tab_by_bin_idxy(dt = tab, x = "x1", y = "x2", xNItv = 50, yNItv = 50)
plot <- ggplot(binned.dt, aes(x = xbinMid, y = ybinMid)) + geom_point(aes(size = N))
return(plot)
}
lst_plots <- list(
plot1 = fcn(dt),
plot2 = fcn(dt[x1 <= 0.7]),
plot3 = fcn(dt[x5 <= 0.3])
)
assign("size.of.plots", object.size(lst_plots), envir = .GlobalEnv)
})
rm(dummyEnv)
# After use, remove and clean up of dataset
rm(dt)
gc();gc()
after.mem.size <- memory.size()
# Memory reports
print(paste0("before.mem.size = ", before.mem.size))
print(paste0("after.mem.size = ", after.mem.size))
print(paste0("plot.objs.size = ", size.of.plots / 1000000))
Я попробовал следующие модификации кода:
- Внутри
fcn
, удаление ggplot
и возвращение NULL
вместо объекта заговора: утечка памяти полностью исчезла. Но это не решение. Мне нужен сюжет.
- Чем меньше запрошенных графиков / меньше столбцов / меньше строк передано в
fcn
, тем меньше утечка памяти.
- Утечка памяти также существует, если я не делаю подмножество и создаю только один объект графика (в примерах я построил график 3).
- После процесса, даже после того, как я позвонил
rm(list = ls())
, память все еще не восстанавливается.
Я хотел бы знать, почему это происходит и как от него избавиться, не ставя под угрозу мою потребность в бинн-графиках и подмножестве dt
для создания разных графиков.
Спасибо за внимание!