Утечка памяти при использовании `ggplot` для больших наборов данных - PullRequest
0 голосов
/ 15 ноября 2018

Я делаю различные 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 для создания разных графиков.

Спасибо за внимание!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...