Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

plumber not releasing memory #496

Closed
LukasK13 opened this issue Oct 9, 2019 · 22 comments
Closed

plumber not releasing memory #496

LukasK13 opened this issue Oct 9, 2019 · 22 comments
Labels
difficulty: advanced Best for maintainers to address difficulty: intermediate Enterprising community members could help help wanted Solution is well-specified enough that any community member could fix out of focus Maintainers will not fix bug, but the issue should remain open until a resolution is found.

Comments

@LukasK13
Copy link

LukasK13 commented Oct 9, 2019

System details

Output of sessioninfo::session_info():

R version 3.6.0 (2019-04-26)
Platform: x86_64-redhat-linux-gnu (64-bit)
Running under: CentOS Linux 7 (Core)

Matrix products: default
BLAS/LAPACK: /usr/lib64/R/lib/libRblas.so

locale:
 [1] LC_CTYPE=C                 LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8     LC_MONETARY=en_US.UTF-8   
 [6] LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] parallel  stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] urltools_1.7.3          httr_1.4.0              lobstr_1.0.1            stringr_1.4.0           yaml_2.2.0              xml2_1.2.0             
 [7] SweetAleRt_1.0          SummeRnote_1.0          shinyWidgets_0.4.8      shinyjs_1.0             shinydashboard_0.7.1    shinyBS_0.61           
[13] sharepointr_1.0.0       RMySQL_0.10.17          rintrojs_0.2.1          RColorBrewer_1.1-2      promises_1.0.1          plotly_4.9.0           
[19] openssl_1.3             officer_0.3.4           lubridate_1.7.4         ldapr_0.1.0             Hmisc_4.2-0             Formula_1.2-3          
[25] survival_2.44-1.1       lattice_0.20-38         jsonlite_1.6            gitlabr_1.1.6           magrittr_1.5            ggplot2_3.1.1          
[31] future_1.12.0           fullcalendaR_1.0        dtplyr_0.0.3            DT_2.0.0                dplyr_0.8.1             directlabels_2018.05.22
[37] dbplyr_1.4.0            DBI_1.0.0               data.table_1.12.4       colourpicker_1.0        bcrypt_1.1              shiny_1.3.2            

loaded via a namespace (and not attached):
 [1] tools_3.6.0         backports_1.1.4     R6_2.4.0            rpart_4.1-15        lazyeval_0.2.2      colorspace_1.4-1    nnet_7.3-12        
 [8] withr_2.1.2         tidyselect_0.2.5    gridExtra_2.3       curl_3.3            compiler_3.6.0      htmlTable_1.13.1    triebeard_0.3.0    
[15] labeling_0.3        scales_1.0.0        checkmate_1.9.3     quadprog_1.5-7      askpass_1.1         plumber_0.4.6       digest_0.6.19      
[22] foreign_0.8-71      base64enc_0.1-3     pkgconfig_2.0.2     htmltools_0.3.6     htmlwidgets_1.3     rlang_0.3.4         rstudioapi_0.10    
[29] crosstalk_1.0.0     acepack_1.4.1       zip_2.0.2           Matrix_1.2-17       Rcpp_1.0.1          munsell_0.5.0       arpr_0.1.1         
[36] stringi_1.4.3       plyr_1.8.4          grid_3.6.0          listenv_0.7.0       crayon_1.3.4        miniUI_0.1.1.1      splines_3.6.0      
[43] knitr_1.22          pillar_1.4.0        uuid_0.1-2          codetools_0.2-16    glue_1.3.1          V8_2.2              latticeExtra_0.6-28
[50] httpuv_1.5.1        gtable_0.3.0        purrr_0.3.2         tidyr_0.8.3         assertthat_0.2.1    xfun_0.7            mime_0.6           
[57] xtable_1.8-4        later_0.8.0         viridisLite_0.3.0   tibble_2.1.1        cluster_2.0.8       globals_0.12.4    

Example application or steps to reproduce the problem

#* @get /getData
function(n = 10000) {
  data=do.call(rbind, replicate(n, mtcars, simplify = F))
  return(data)
}

Describe the problem in detail

Requesting large datasets via plumber results in a large memory consumption of the plumber process which is ok. After the request ist finished, this memory is not released by the garbage collection. This means, if 4 GB were allocated for serving the request, the process will keep the allocated memory forever until restarted. Even after requesting a small dataset after the large one, the memory won't be released. I'm not quite sure if this is actually a bug or if I am doing something wrong.

Thanks for your help!

@shrektan
Copy link
Contributor

shrektan commented Oct 9, 2019

I think I experienced something similar before but never had a chance to take a deep look at it... The memory is not increased infinitely but is larger than my expectation. However, since I use plumber on Docker containers, I'm not sure it's because the docker container does not collect the memory in time or an issue of plumber...

@schloerke
Copy link
Collaborator

I am able to reproduce this as well. It is not clear where it is happening. Profvis shows a minor mem leak compared to the process memory increase. @wch and I will be investigating.

Even using the route below causes the mem leak. So it's not caused by creating the data. Seems to be when transferring the data.

big_dt <- dplyr::bind_rows(replicate(10000, mtcars, simplify = F))
#* @get /getData3
function() {
  return(big_dt)
}

@LukasK13
Copy link
Author

LukasK13 commented Oct 9, 2019

Thank you both for looking into this.

@shrektan Originally, I experienced this using a docker container, but I switched to simple hosting for debugging purposes, where I was able to reproduce the error. So it's definitely a plumber problem.

@schloerke I tried calling gc() in the beginning of each request, so old data from the last request should be removed and memory released. Therefore I made a request for a large dataset in the first place (500 MB) and a small dataset (10 MB) afterwards. I noticed, that some memory was actually released (about 40%) but a significant amount was still allocated. Using gc() in combination with a postserialize hook didn't help either. This tells me, that the there is a scope which aggregates old data without becoming out of scope and that's why it's not affected by calling gc(). What do you think?

Let me know, if I can help finding the cause.

@schloerke
Copy link
Collaborator

schloerke commented Oct 9, 2019

memleak.png
memleak

  • X Axis number of attempts at route
  • Y Axis Memory usage
  • Facets
    • rbind: original /getData where all data is generated, rbind'ed, and returned
    • bind_rows: Similar to the original /getData where all data is generated, dplyr::bind_rows'ed, and returned
    • return: Similar to /bind_rows, but the data is already processed. So only the data is returned.

Thoughts:

  • Each plumber process hovered around 75mb of R objects throughout the whole process. This was checked with pryr::mem_used(). Plumber does not have any compiled code, so this is the number plumber cares about.
  • The R process is gaining overall memory usage. This can be tracked by memuse::Sys.procmem(). I believe this is cause by the R process's cache buffers. Since the leak is not linear and is more asymptotic in shape, this pushes me to believe it is R trying to handle the large influx of memory.
    • This large increase in process memory can be replicated using a for loop and generating the data as /getData does and finally removing the variable. (Without adding plumber in the mix). Even after gc(), the process has over a GB of memory usage.
Final thought

Given that pryr::mem_used() is not increasing during usage and plumber does not have compiled code, I'm taking the stance that plumber is not the culprit. I do not know where to dig further as similar behavior can be reproduced with stock R packages. (Unfortunately, there still is an unexpected increase in memory for the R process.)


I've added a file (and execution output) below to reproduce the whole investigation.

`mem_test.R` file
library(magrittr)

n <- 100
routes <- c("rbind", "bind_rows", "return")

init_file <- function() {
  cat("route, row, mem_used, procmem, time\n", file = "memleak.csv")
}

cat_row <- function(route, i, mem_used, procmem, time) {
  row <- paste(route, i, mem_used, procmem, time, sep = ", ")
  cat(row, "\n", file = "memleak.csv", append = TRUE, sep = "")
}

profile_plumber <- function(route = "getData", port = 12321) {
  pr <- progress::progress_bar$new(
    total = n,
    format = "[:bar] :current/:total eta::eta; :elapsedfull; mem_used: :mem_used; procmem: :procmem\n",
    show_after = 0,
    clear = FALSE
  )
  now <- as.numeric(Sys.time())
  base_url <- paste0("127.0.0.1:", port, "/")
  for (i in 1:n) {
    # ask route
    now <- as.numeric(Sys.time())
    httr::GET(paste0(base_url, route))
    after <- as.numeric(Sys.time())
    # get mem stats
    mem_used <- httr::GET(paste0(base_url, "mem_used")) %>% httr::content() %>% magrittr::extract2(1)
    procmem <- httr::GET(paste0(base_url, "procmem")) %>% httr::content() %>% magrittr::extract2(1)
    pr$tick(tokens = list(
      mem_used = mem_used,
      procmem = procmem
    ))
    # save
    cat_row(route, i, mem_used, procmem, after - now)
  }
}

profile_plot <- function() {
  library(ggplot2)
  readr::read_csv("memleak.csv") %>%
    dplyr::select(-time) %>%
    tidyr::pivot_longer(names_to = "fn", values_to = "memory", c("mem_used", "procmem")) %>%
    dplyr::mutate(
      route = factor(route, levels = routes),
      memory = sub(" M[i]*B", "", memory) %>% as.numeric()
    ) %>%
    {
      dt <- .
      ggplot(dt, aes(row, memory, color = fn)) +
        geom_line() +
        facet_grid(. ~ route) +
        labs(y = "memory (MiB)")
    } %>%
    ggsave(filename = paste0("memleak.png"), width = 10, height = 6)
}


cat(file = "plumber.R",
'#* @get /rbind
function(n = 10000) {
  data=do.call(rbind, replicate(n, mtcars, simplify = F))
  return(data)
}
#* @get /bind_rows
function(n = 10000) {
  dt <- replicate(n, mtcars, simplify = F)
  data <- dplyr::bind_rows(dt)
  return(data)
}

big_dt <- dplyr::bind_rows(replicate(10000, mtcars, simplify = F))
#* @get /return
function() {
  return(big_dt)
}

#* @get /procmem
function() {
  # basically calling ps u -p `Sys.getpid()` and getting the rss value
  current_mem <- memuse::swap.unit(memuse::Sys.procmem()[[1]], unit = "MiB")
  size_mem <- memuse::mu.size(current_mem)
  unit_mem <- memuse::mu.unit(current_mem)
  mem <- paste0(round(size_mem, 1), " ", unit_mem)
  return(mem)
}

#* @get /mem_used
function() {
  capture.output({print(pryr::mem_used())})
}
')


port <- httpuv::randomPort()
init_file()
for (route in routes) {
  message("Starting plumber API")
  proc <- callr::r_bg(function(p) {
    plumber::plumb("plumber.R")$run(port = p)
  }, list(p = port))

  message("...sleeping...")
  Sys.sleep(3)

  message("Profiling server: ", route)
  profile_plumber(route, port)

  message("Stopping plumber API")
  proc$kill()

  message("...sleeping...")
  Sys.sleep(3)
}
message("Generate Image")
profile_plot()
Execution output
mem_test: Rscript mem_test.R 
Starting plumber API
...sleeping...
Profiling server: rbind
[------------] 1/100 eta: 1s; 00:00:00; mem_used: 75.8 MB; procmem: 572.5 MiB
[------------] 2/100 eta: 3m; 00:00:03; mem_used: 78.7 MB; procmem: 705.7 MiB
[------------] 3/100 eta: 4m; 00:00:07; mem_used: 78.7 MB; procmem: 778.5 MiB
[>-------------] 4/100 eta: 4m; 00:00:10; mem_used: 78.7 MB; procmem: 848 MiB
[>-----------] 5/100 eta: 5m; 00:00:14; mem_used: 78.7 MB; procmem: 874.4 MiB
[>-------------] 6/100 eta: 5m; 00:00:17; mem_used: 78.7 MB; procmem: 891 MiB
[>-----------] 7/100 eta: 5m; 00:00:21; mem_used: 78.7 MB; procmem: 919.9 MiB
[>-----------] 8/100 eta: 5m; 00:00:25; mem_used: 78.7 MB; procmem: 927.4 MiB
[>-----------] 9/100 eta: 5m; 00:00:28; mem_used: 78.7 MB; procmem: 944.8 MiB
[>----------] 10/100 eta: 5m; 00:00:32; mem_used: 78.7 MB; procmem: 944.5 MiB
[>----------] 11/100 eta: 5m; 00:00:35; mem_used: 78.7 MB; procmem: 957.1 MiB
[>----------] 12/100 eta: 5m; 00:00:39; mem_used: 78.7 MB; procmem: 975.3 MiB
[>---------] 13/100 eta: 5m; 00:00:42; mem_used: 78.7 MB; procmem: 1025.8 MiB
[>---------] 14/100 eta: 5m; 00:00:46; mem_used: 78.7 MB; procmem: 1064.4 MiB
[=>----------] 15/100 eta: 5m; 00:00:50; mem_used: 78.7 MB; procmem: 1064 MiB
[=>--------] 16/100 eta: 5m; 00:00:53; mem_used: 78.7 MB; procmem: 1081.7 MiB
[=>--------] 17/100 eta: 5m; 00:00:57; mem_used: 78.7 MB; procmem: 1099.5 MiB
[=>--------] 18/100 eta: 5m; 00:01:00; mem_used: 78.7 MB; procmem: 1140.4 MiB
[=>--------] 19/100 eta: 5m; 00:01:04; mem_used: 78.7 MB; procmem: 1141.2 MiB
[=>--------] 20/100 eta: 5m; 00:01:08; mem_used: 78.7 MB; procmem: 1145.5 MiB
[=>--------] 21/100 eta: 5m; 00:01:12; mem_used: 78.7 MB; procmem: 1154.2 MiB
[=>--------] 22/100 eta: 4m; 00:01:15; mem_used: 78.7 MB; procmem: 1155.7 MiB
[=>--------] 23/100 eta: 4m; 00:01:19; mem_used: 78.7 MB; procmem: 1147.8 MiB
[==>---------] 24/100 eta: 4m; 00:01:23; mem_used: 78.7 MB; procmem: 1149 MiB
[=>--------] 25/100 eta: 4m; 00:01:26; mem_used: 78.7 MB; procmem: 1152.3 MiB
[==>-------] 26/100 eta: 4m; 00:01:30; mem_used: 78.7 MB; procmem: 1142.7 MiB
[==>-------] 27/100 eta: 4m; 00:01:34; mem_used: 78.7 MB; procmem: 1153.7 MiB
[==>---------] 28/100 eta: 4m; 00:01:38; mem_used: 78.7 MB; procmem: 1168 MiB
[==>-------] 29/100 eta: 4m; 00:01:41; mem_used: 78.7 MB; procmem: 1183.9 MiB
[==>-------] 30/100 eta: 4m; 00:01:45; mem_used: 78.7 MB; procmem: 1193.4 MiB
[==>-------] 31/100 eta: 4m; 00:01:49; mem_used: 78.7 MB; procmem: 1196.4 MiB
[==>-------] 32/100 eta: 4m; 00:01:52; mem_used: 78.7 MB; procmem: 1193.6 MiB
[==>-------] 33/100 eta: 4m; 00:01:56; mem_used: 78.7 MB; procmem: 1199.1 MiB
[==>-------] 34/100 eta: 4m; 00:02:00; mem_used: 78.7 MB; procmem: 1197.7 MiB
[===>------] 35/100 eta: 4m; 00:02:04; mem_used: 78.7 MB; procmem: 1200.4 MiB
[===>------] 36/100 eta: 4m; 00:02:07; mem_used: 78.7 MB; procmem: 1247.1 MiB
[===>------] 37/100 eta: 4m; 00:02:11; mem_used: 78.7 MB; procmem: 1255.6 MiB
[===>------] 38/100 eta: 4m; 00:02:15; mem_used: 78.7 MB; procmem: 1258.1 MiB
[===>------] 39/100 eta: 4m; 00:02:18; mem_used: 78.7 MB; procmem: 1259.7 MiB
[===>------] 40/100 eta: 4m; 00:02:22; mem_used: 78.7 MB; procmem: 1268.7 MiB
[===>------] 41/100 eta: 3m; 00:02:25; mem_used: 78.7 MB; procmem: 1269.5 MiB
[===>------] 42/100 eta: 3m; 00:02:29; mem_used: 78.7 MB; procmem: 1279.8 MiB
[===>------] 43/100 eta: 3m; 00:02:33; mem_used: 78.7 MB; procmem: 1273.6 MiB
[====>-------] 44/100 eta: 3m; 00:02:36; mem_used: 78.7 MB; procmem: 1265 MiB
[===>------] 45/100 eta: 3m; 00:02:40; mem_used: 78.7 MB; procmem: 1283.5 MiB
[=====>------] 46/100 eta: 3m; 00:02:44; mem_used: 78.7 MB; procmem: 1293 MiB
[====>-----] 47/100 eta: 3m; 00:02:48; mem_used: 78.7 MB; procmem: 1295.9 MiB
[====>-----] 48/100 eta: 3m; 00:02:51; mem_used: 78.7 MB; procmem: 1306.7 MiB
[====>-----] 49/100 eta: 3m; 00:02:55; mem_used: 78.7 MB; procmem: 1308.6 MiB
[====>-----] 50/100 eta: 3m; 00:02:59; mem_used: 78.7 MB; procmem: 1301.7 MiB
[====>-----] 51/100 eta: 3m; 00:03:03; mem_used: 78.7 MB; procmem: 1311.9 MiB
[====>-----] 52/100 eta: 3m; 00:03:06; mem_used: 78.7 MB; procmem: 1319.2 MiB
[====>-----] 53/100 eta: 3m; 00:03:10; mem_used: 78.7 MB; procmem: 1295.6 MiB
[====>-----] 54/100 eta: 3m; 00:03:14; mem_used: 78.7 MB; procmem: 1290.3 MiB
[=====>----] 55/100 eta: 3m; 00:03:17; mem_used: 78.7 MB; procmem: 1285.4 MiB
[=====>----] 56/100 eta: 3m; 00:03:21; mem_used: 78.7 MB; procmem: 1297.3 MiB
[=====>----] 57/100 eta: 3m; 00:03:25; mem_used: 78.7 MB; procmem: 1294.6 MiB
[=====>----] 58/100 eta: 3m; 00:03:28; mem_used: 78.7 MB; procmem: 1312.2 MiB
[======>-----] 59/100 eta: 2m; 00:03:32; mem_used: 78.7 MB; procmem: 1300 MiB
[=====>----] 60/100 eta: 2m; 00:03:36; mem_used: 78.7 MB; procmem: 1304.5 MiB
[======>-----] 61/100 eta: 2m; 00:03:40; mem_used: 78.7 MB; procmem: 1307 MiB
[=====>----] 62/100 eta: 2m; 00:03:44; mem_used: 78.7 MB; procmem: 1296.7 MiB
[=====>----] 63/100 eta: 2m; 00:03:47; mem_used: 78.7 MB; procmem: 1290.7 MiB
[=====>----] 64/100 eta: 2m; 00:03:51; mem_used: 78.7 MB; procmem: 1300.5 MiB
[=====>----] 65/100 eta: 2m; 00:03:55; mem_used: 78.7 MB; procmem: 1304.8 MiB
[======>---] 66/100 eta: 2m; 00:03:58; mem_used: 78.7 MB; procmem: 1305.3 MiB
[======>---] 67/100 eta: 2m; 00:04:02; mem_used: 78.7 MB; procmem: 1308.1 MiB
[======>---] 68/100 eta: 2m; 00:04:06; mem_used: 78.7 MB; procmem: 1316.6 MiB
[======>---] 69/100 eta: 2m; 00:04:10; mem_used: 78.7 MB; procmem: 1309.4 MiB
[======>---] 70/100 eta: 2m; 00:04:13; mem_used: 78.7 MB; procmem: 1305.4 MiB
[======>---] 71/100 eta: 2m; 00:04:17; mem_used: 78.7 MB; procmem: 1320.4 MiB
[======>---] 72/100 eta: 2m; 00:04:21; mem_used: 78.7 MB; procmem: 1319.1 MiB
[======>---] 73/100 eta: 2m; 00:04:24; mem_used: 78.7 MB; procmem: 1313.2 MiB
[======>---] 74/100 eta: 2m; 00:04:28; mem_used: 78.7 MB; procmem: 1308.8 MiB
[=======>--] 75/100 eta: 2m; 00:04:32; mem_used: 78.7 MB; procmem: 1317.2 MiB
[=======>--] 76/100 eta: 1m; 00:04:36; mem_used: 78.7 MB; procmem: 1323.8 MiB
[=======>--] 77/100 eta: 1m; 00:04:40; mem_used: 78.7 MB; procmem: 1314.1 MiB
[=======>--] 78/100 eta: 1m; 00:04:44; mem_used: 78.7 MB; procmem: 1308.8 MiB
[=======>--] 79/100 eta: 1m; 00:04:48; mem_used: 78.7 MB; procmem: 1310.6 MiB
[=======>--] 80/100 eta: 1m; 00:04:51; mem_used: 78.7 MB; procmem: 1314.1 MiB
[=========>--] 81/100 eta: 1m; 00:04:55; mem_used: 78.7 MB; procmem: 1321 MiB
[=======>--] 82/100 eta: 1m; 00:04:59; mem_used: 78.7 MB; procmem: 1322.5 MiB
[=======>--] 83/100 eta: 1m; 00:05:02; mem_used: 78.7 MB; procmem: 1320.7 MiB
[=======>--] 84/100 eta: 1m; 00:05:06; mem_used: 78.7 MB; procmem: 1326.6 MiB
[=======>--] 85/100 eta: 1m; 00:05:10; mem_used: 78.7 MB; procmem: 1320.2 MiB
[=========>--] 86/100 eta: 1m; 00:05:14; mem_used: 78.7 MB; procmem: 1314 MiB
[========>-] 87/100 eta:47s; 00:05:17; mem_used: 78.7 MB; procmem: 1323.8 MiB
[========>-] 88/100 eta:44s; 00:05:21; mem_used: 78.7 MB; procmem: 1235.6 MiB
[==========>-] 89/100 eta:40s; 00:05:25; mem_used: 78.7 MB; procmem: 1271 MiB
[========>-] 90/100 eta:37s; 00:05:28; mem_used: 78.7 MB; procmem: 1291.4 MiB
[========>-] 91/100 eta:33s; 00:05:32; mem_used: 78.7 MB; procmem: 1289.4 MiB
[========>-] 92/100 eta:29s; 00:05:36; mem_used: 78.7 MB; procmem: 1298.9 MiB
[========>-] 93/100 eta:26s; 00:05:39; mem_used: 78.7 MB; procmem: 1299.7 MiB
[========>-] 94/100 eta:22s; 00:05:43; mem_used: 78.7 MB; procmem: 1263.5 MiB
[=========>] 95/100 eta:18s; 00:05:47; mem_used: 78.7 MB; procmem: 1285.3 MiB
[=========>] 96/100 eta:15s; 00:05:51; mem_used: 78.7 MB; procmem: 1019.7 MiB
[=========>] 97/100 eta:11s; 00:05:55; mem_used: 78.7 MB; procmem: 1171.1 MiB
[=========>] 98/100 eta: 7s; 00:05:59; mem_used: 78.7 MB; procmem: 1196.3 MiB
[==========>] 99/100 eta: 4s; 00:06:04; mem_used: 78.7 MB; procmem: 933.3 MiB
[=========] 100/100 eta: 0s; 00:06:08; mem_used: 78.7 MB; procmem: 1007.3 MiB

Stopping plumber API
...sleeping...
Starting plumber API
...sleeping...
Profiling server: bind_rows
[------------] 1/100 eta: 0s; 00:00:00; mem_used: 71.9 MB; procmem: 350.2 MiB
[------------] 2/100 eta: 1m; 00:00:01; mem_used: 74.8 MB; procmem: 385.8 MiB
[------------] 3/100 eta: 1m; 00:00:02; mem_used: 74.8 MB; procmem: 408.9 MiB
[------------] 4/100 eta: 1m; 00:00:03; mem_used: 74.8 MB; procmem: 414.7 MiB
[>-----------] 5/100 eta: 1m; 00:00:04; mem_used: 74.8 MB; procmem: 432.7 MiB
[>-----------] 6/100 eta: 1m; 00:00:05; mem_used: 74.8 MB; procmem: 458.3 MiB
[>-----------] 7/100 eta: 1m; 00:00:06; mem_used: 74.8 MB; procmem: 463.3 MiB
[>-----------] 8/100 eta: 1m; 00:00:07; mem_used: 74.8 MB; procmem: 472.1 MiB
[>-----------] 9/100 eta: 1m; 00:00:08; mem_used: 74.8 MB; procmem: 472.2 MiB
[>------------] 10/100 eta: 1m; 00:00:09; mem_used: 74.8 MB; procmem: 482 MiB
[>----------] 11/100 eta: 1m; 00:00:10; mem_used: 74.8 MB; procmem: 484.2 MiB
[=>-----------] 12/100 eta: 1m; 00:00:12; mem_used: 74.8 MB; procmem: 494 MiB
[=>-----------] 13/100 eta: 1m; 00:00:13; mem_used: 74.8 MB; procmem: 494 MiB
[=>---------] 14/100 eta: 1m; 00:00:14; mem_used: 74.8 MB; procmem: 501.1 MiB
[=>---------] 15/100 eta: 1m; 00:00:15; mem_used: 74.8 MB; procmem: 519.1 MiB
[=>---------] 16/100 eta: 1m; 00:00:16; mem_used: 74.8 MB; procmem: 519.9 MiB
[=>---------] 17/100 eta: 1m; 00:00:17; mem_used: 74.8 MB; procmem: 529.7 MiB
[=>---------] 18/100 eta: 1m; 00:00:17; mem_used: 74.8 MB; procmem: 534.6 MiB
[=>-----------] 19/100 eta: 1m; 00:00:19; mem_used: 74.8 MB; procmem: 542 MiB
[==>----------] 20/100 eta: 1m; 00:00:20; mem_used: 74.8 MB; procmem: 542 MiB
[==>----------] 21/100 eta: 1m; 00:00:21; mem_used: 74.8 MB; procmem: 542 MiB
[=>---------] 22/100 eta: 1m; 00:00:22; mem_used: 74.8 MB; procmem: 542.1 MiB
[==>--------] 23/100 eta: 1m; 00:00:23; mem_used: 74.8 MB; procmem: 544.5 MiB
[==>----------] 24/100 eta: 1m; 00:00:24; mem_used: 74.8 MB; procmem: 547 MiB
[==>--------] 25/100 eta: 1m; 00:00:25; mem_used: 74.8 MB; procmem: 547.6 MiB
[==>--------] 26/100 eta: 1m; 00:00:26; mem_used: 74.8 MB; procmem: 547.6 MiB
[===>---------] 27/100 eta: 1m; 00:00:27; mem_used: 74.8 MB; procmem: 550 MiB
[==>--------] 28/100 eta: 1m; 00:00:28; mem_used: 74.8 MB; procmem: 554.9 MiB
[===>---------] 29/100 eta: 1m; 00:00:29; mem_used: 74.8 MB; procmem: 555 MiB
[===>---------] 30/100 eta: 1m; 00:00:30; mem_used: 74.8 MB; procmem: 555 MiB
[==>--------] 31/100 eta: 1m; 00:00:31; mem_used: 74.8 MB; procmem: 555.1 MiB
[===>-------] 32/100 eta: 1m; 00:00:32; mem_used: 74.8 MB; procmem: 555.1 MiB
[===>-------] 33/100 eta: 1m; 00:00:33; mem_used: 74.8 MB; procmem: 555.1 MiB
[===>-------] 34/100 eta: 1m; 00:00:34; mem_used: 74.8 MB; procmem: 555.1 MiB
[===>-------] 35/100 eta: 1m; 00:00:35; mem_used: 74.8 MB; procmem: 555.1 MiB
[===>-------] 36/100 eta: 1m; 00:00:36; mem_used: 74.8 MB; procmem: 547.1 MiB
[===>-------] 37/100 eta: 1m; 00:00:37; mem_used: 74.8 MB; procmem: 547.1 MiB
[====>--------] 38/100 eta: 1m; 00:00:38; mem_used: 74.8 MB; procmem: 552 MiB
[====>--------] 39/100 eta: 1m; 00:00:39; mem_used: 74.8 MB; procmem: 552 MiB
[===>-------] 40/100 eta: 1m; 00:00:41; mem_used: 74.8 MB; procmem: 552.2 MiB
[====>--------] 41/100 eta: 1m; 00:00:42; mem_used: 74.8 MB; procmem: 557 MiB
[====>--------] 42/100 eta: 1m; 00:00:43; mem_used: 74.8 MB; procmem: 557 MiB
[=====>-------] 43/100 eta: 1m; 00:00:44; mem_used: 74.8 MB; procmem: 557 MiB
[=====>-------] 44/100 eta: 1m; 00:00:45; mem_used: 74.8 MB; procmem: 557 MiB
[====>------] 45/100 eta: 1m; 00:00:46; mem_used: 74.8 MB; procmem: 559.5 MiB
[====>------] 46/100 eta: 1m; 00:00:47; mem_used: 74.8 MB; procmem: 564.4 MiB
[====>------] 47/100 eta: 1m; 00:00:48; mem_used: 74.8 MB; procmem: 564.4 MiB
[====>------] 48/100 eta: 1m; 00:00:49; mem_used: 74.8 MB; procmem: 564.4 MiB
[====>------] 49/100 eta: 1m; 00:00:50; mem_used: 74.8 MB; procmem: 564.4 MiB
[=====>-----] 50/100 eta: 1m; 00:00:51; mem_used: 74.8 MB; procmem: 565.4 MiB
[=====>-----] 51/100 eta: 1m; 00:00:52; mem_used: 74.8 MB; procmem: 566.5 MiB
[=====>-----] 52/100 eta:50s; 00:00:53; mem_used: 74.8 MB; procmem: 566.5 MiB
[=====>-----] 53/100 eta:49s; 00:00:54; mem_used: 74.8 MB; procmem: 564.4 MiB
[=====>-----] 54/100 eta:48s; 00:00:55; mem_used: 74.8 MB; procmem: 565.4 MiB
[=====>-----] 55/100 eta:47s; 00:00:56; mem_used: 74.8 MB; procmem: 569.8 MiB
[=====>-----] 56/100 eta:46s; 00:00:57; mem_used: 74.8 MB; procmem: 572.5 MiB
[=====>-----] 57/100 eta:44s; 00:00:58; mem_used: 74.8 MB; procmem: 580.4 MiB
[=====>-----] 58/100 eta:43s; 00:01:00; mem_used: 74.8 MB; procmem: 580.4 MiB
[=====>-----] 59/100 eta:42s; 00:01:01; mem_used: 74.8 MB; procmem: 580.4 MiB
[======>----] 60/100 eta:41s; 00:01:02; mem_used: 74.8 MB; procmem: 580.4 MiB
[======>----] 61/100 eta:40s; 00:01:03; mem_used: 74.8 MB; procmem: 580.4 MiB
[======>----] 62/100 eta:39s; 00:01:04; mem_used: 74.8 MB; procmem: 585.3 MiB
[======>----] 63/100 eta:38s; 00:01:05; mem_used: 74.8 MB; procmem: 585.4 MiB
[======>----] 64/100 eta:37s; 00:01:06; mem_used: 74.8 MB; procmem: 585.4 MiB
[======>----] 65/100 eta:36s; 00:01:07; mem_used: 74.8 MB; procmem: 585.4 MiB
[======>----] 66/100 eta:35s; 00:01:08; mem_used: 74.8 MB; procmem: 585.4 MiB
[======>----] 67/100 eta:34s; 00:01:09; mem_used: 74.8 MB; procmem: 587.9 MiB
[======>----] 68/100 eta:33s; 00:01:10; mem_used: 74.8 MB; procmem: 579.9 MiB
[=======>---] 69/100 eta:32s; 00:01:11; mem_used: 74.8 MB; procmem: 581.2 MiB
[=======>---] 70/100 eta:31s; 00:01:12; mem_used: 74.8 MB; procmem: 581.2 MiB
[=======>---] 71/100 eta:30s; 00:01:13; mem_used: 74.8 MB; procmem: 581.2 MiB
[=======>---] 72/100 eta:29s; 00:01:14; mem_used: 74.8 MB; procmem: 581.2 MiB
[=======>---] 73/100 eta:28s; 00:01:15; mem_used: 74.8 MB; procmem: 581.2 MiB
[=======>---] 74/100 eta:27s; 00:01:16; mem_used: 74.8 MB; procmem: 581.2 MiB
[=======>---] 75/100 eta:26s; 00:01:17; mem_used: 74.8 MB; procmem: 573.2 MiB
[=======>---] 76/100 eta:25s; 00:01:18; mem_used: 74.8 MB; procmem: 573.3 MiB
[=======>---] 77/100 eta:24s; 00:01:20; mem_used: 74.8 MB; procmem: 573.3 MiB
[========>--] 78/100 eta:23s; 00:01:21; mem_used: 74.8 MB; procmem: 573.3 MiB
[========>--] 79/100 eta:22s; 00:01:22; mem_used: 74.8 MB; procmem: 573.3 MiB
[========>--] 80/100 eta:21s; 00:01:23; mem_used: 74.8 MB; procmem: 573.3 MiB
[========>--] 81/100 eta:20s; 00:01:24; mem_used: 74.8 MB; procmem: 575.8 MiB
[========>--] 82/100 eta:19s; 00:01:25; mem_used: 74.8 MB; procmem: 575.8 MiB
[========>--] 83/100 eta:18s; 00:01:26; mem_used: 74.8 MB; procmem: 575.8 MiB
[========>--] 84/100 eta:17s; 00:01:27; mem_used: 74.8 MB; procmem: 575.8 MiB
[========>--] 85/100 eta:16s; 00:01:28; mem_used: 74.8 MB; procmem: 575.8 MiB
[==========>--] 86/100 eta:15s; 00:01:29; mem_used: 74.8 MB; procmem: 576 MiB
[==========>--] 87/100 eta:14s; 00:01:30; mem_used: 74.8 MB; procmem: 576 MiB
[=========>-] 88/100 eta:13s; 00:01:31; mem_used: 74.8 MB; procmem: 579.5 MiB
[===========>-] 89/100 eta:11s; 00:01:32; mem_used: 74.8 MB; procmem: 576 MiB
[===========>-] 90/100 eta:10s; 00:01:33; mem_used: 74.8 MB; procmem: 576 MiB
[=========>-] 91/100 eta: 9s; 00:01:34; mem_used: 74.8 MB; procmem: 581.8 MiB
[=========>-] 92/100 eta: 8s; 00:01:35; mem_used: 74.8 MB; procmem: 589.2 MiB
[=========>-] 93/100 eta: 7s; 00:01:36; mem_used: 74.8 MB; procmem: 589.2 MiB
[=========>-] 94/100 eta: 6s; 00:01:37; mem_used: 74.8 MB; procmem: 589.2 MiB
[=========>-] 95/100 eta: 5s; 00:01:39; mem_used: 74.8 MB; procmem: 589.2 MiB
[==========>] 96/100 eta: 4s; 00:01:40; mem_used: 74.8 MB; procmem: 589.2 MiB
[==========>] 97/100 eta: 3s; 00:01:41; mem_used: 74.8 MB; procmem: 589.2 MiB
[==========>] 98/100 eta: 2s; 00:01:42; mem_used: 74.8 MB; procmem: 589.2 MiB
[==========>] 99/100 eta: 1s; 00:01:43; mem_used: 74.8 MB; procmem: 590.4 MiB
[==========] 100/100 eta: 0s; 00:01:44; mem_used: 74.8 MB; procmem: 598.5 MiB

Stopping plumber API
...sleeping...
Starting plumber API
...sleeping...
Profiling server: return
[------------] 1/100 eta: 0s; 00:00:00; mem_used: 71.9 MB; procmem: 284.8 MiB
[------------] 2/100 eta: 1m; 00:00:01; mem_used: 74.8 MB; procmem: 315.4 MiB
[------------] 3/100 eta: 1m; 00:00:02; mem_used: 74.8 MB; procmem: 333.6 MiB
[------------] 4/100 eta: 1m; 00:00:03; mem_used: 74.8 MB; procmem: 336.6 MiB
[>-----------] 5/100 eta: 1m; 00:00:04; mem_used: 74.8 MB; procmem: 339.9 MiB
[>-----------] 6/100 eta: 1m; 00:00:05; mem_used: 74.8 MB; procmem: 343.2 MiB
[>-----------] 7/100 eta: 1m; 00:00:06; mem_used: 74.8 MB; procmem: 346.6 MiB
[>-----------] 8/100 eta: 1m; 00:00:07; mem_used: 74.8 MB; procmem: 350.2 MiB
[>-----------] 9/100 eta: 1m; 00:00:07; mem_used: 74.8 MB; procmem: 351.9 MiB
[>------------] 10/100 eta: 1m; 00:00:08; mem_used: 74.8 MB; procmem: 352 MiB
[>----------] 11/100 eta: 1m; 00:00:09; mem_used: 74.8 MB; procmem: 354.4 MiB
[>----------] 12/100 eta: 1m; 00:00:10; mem_used: 74.8 MB; procmem: 354.6 MiB
[>----------] 13/100 eta: 1m; 00:00:11; mem_used: 74.8 MB; procmem: 354.6 MiB
[=>---------] 14/100 eta: 1m; 00:00:12; mem_used: 74.8 MB; procmem: 357.3 MiB
[=>---------] 15/100 eta: 1m; 00:00:13; mem_used: 74.8 MB; procmem: 359.7 MiB
[=>---------] 16/100 eta: 1m; 00:00:14; mem_used: 74.8 MB; procmem: 359.8 MiB
[=>---------] 17/100 eta: 1m; 00:00:15; mem_used: 74.8 MB; procmem: 359.8 MiB
[=>---------] 18/100 eta: 1m; 00:00:16; mem_used: 74.8 MB; procmem: 359.8 MiB
[=>---------] 19/100 eta: 1m; 00:00:17; mem_used: 74.8 MB; procmem: 362.3 MiB
[=>---------] 20/100 eta: 1m; 00:00:18; mem_used: 74.8 MB; procmem: 367.1 MiB
[=>---------] 21/100 eta: 1m; 00:00:19; mem_used: 74.8 MB; procmem: 367.9 MiB
[=>---------] 22/100 eta: 1m; 00:00:20; mem_used: 74.8 MB; procmem: 367.9 MiB
[==>--------] 23/100 eta: 1m; 00:00:21; mem_used: 74.8 MB; procmem: 367.9 MiB
[==>--------] 24/100 eta: 1m; 00:00:22; mem_used: 74.8 MB; procmem: 367.9 MiB
[==>--------] 25/100 eta: 1m; 00:00:23; mem_used: 74.8 MB; procmem: 367.9 MiB
[==>--------] 26/100 eta: 1m; 00:00:24; mem_used: 74.8 MB; procmem: 368.6 MiB
[==>--------] 27/100 eta: 1m; 00:00:25; mem_used: 74.8 MB; procmem: 368.6 MiB
[==>--------] 28/100 eta: 1m; 00:00:26; mem_used: 74.8 MB; procmem: 368.6 MiB
[==>--------] 29/100 eta: 1m; 00:00:27; mem_used: 74.8 MB; procmem: 368.8 MiB
[==>--------] 30/100 eta: 1m; 00:00:28; mem_used: 74.8 MB; procmem: 369.4 MiB
[==>--------] 31/100 eta: 1m; 00:00:29; mem_used: 74.8 MB; procmem: 371.8 MiB
[===>-------] 32/100 eta: 1m; 00:00:30; mem_used: 74.8 MB; procmem: 371.8 MiB
[===>-------] 33/100 eta: 1m; 00:00:31; mem_used: 74.8 MB; procmem: 371.8 MiB
[===>-------] 34/100 eta: 1m; 00:00:32; mem_used: 74.8 MB; procmem: 371.8 MiB
[===>-------] 35/100 eta: 1m; 00:00:33; mem_used: 74.8 MB; procmem: 371.8 MiB
[===>-------] 36/100 eta: 1m; 00:00:34; mem_used: 74.8 MB; procmem: 372.5 MiB
[===>-------] 37/100 eta: 1m; 00:00:35; mem_used: 74.8 MB; procmem: 372.5 MiB
[===>-------] 38/100 eta: 1m; 00:00:35; mem_used: 74.8 MB; procmem: 372.5 MiB
[===>-------] 39/100 eta: 1m; 00:00:37; mem_used: 74.8 MB; procmem: 372.5 MiB
[====>--------] 40/100 eta: 1m; 00:00:38; mem_used: 74.8 MB; procmem: 375 MiB
[====>------] 41/100 eta: 1m; 00:00:38; mem_used: 74.8 MB; procmem: 377.4 MiB
[====>------] 42/100 eta: 1m; 00:00:39; mem_used: 74.8 MB; procmem: 378.2 MiB
[====>------] 43/100 eta: 1m; 00:00:40; mem_used: 74.8 MB; procmem: 378.5 MiB
[====>------] 44/100 eta: 1m; 00:00:41; mem_used: 74.8 MB; procmem: 383.4 MiB
[====>------] 45/100 eta: 1m; 00:00:42; mem_used: 74.8 MB; procmem: 383.4 MiB
[====>------] 46/100 eta: 1m; 00:00:43; mem_used: 74.8 MB; procmem: 385.8 MiB
[====>------] 47/100 eta: 1m; 00:00:44; mem_used: 74.8 MB; procmem: 386.2 MiB
[====>------] 48/100 eta:50s; 00:00:45; mem_used: 74.8 MB; procmem: 386.2 MiB
[====>------] 49/100 eta:49s; 00:00:46; mem_used: 74.8 MB; procmem: 386.2 MiB
[=====>-----] 50/100 eta:48s; 00:00:47; mem_used: 74.8 MB; procmem: 386.2 MiB
[=====>-----] 51/100 eta:47s; 00:00:48; mem_used: 74.8 MB; procmem: 386.2 MiB
[=====>-----] 52/100 eta:46s; 00:00:49; mem_used: 74.8 MB; procmem: 386.2 MiB
[=====>-----] 53/100 eta:45s; 00:00:50; mem_used: 74.8 MB; procmem: 386.2 MiB
[=====>-----] 54/100 eta:44s; 00:00:51; mem_used: 74.8 MB; procmem: 386.2 MiB
[=====>-----] 55/100 eta:43s; 00:00:52; mem_used: 74.8 MB; procmem: 386.2 MiB
[=====>-----] 56/100 eta:42s; 00:00:53; mem_used: 74.8 MB; procmem: 386.2 MiB
[=====>-----] 57/100 eta:41s; 00:00:54; mem_used: 74.8 MB; procmem: 386.2 MiB
[=====>-----] 58/100 eta:40s; 00:00:55; mem_used: 74.8 MB; procmem: 386.2 MiB
[=====>-----] 59/100 eta:39s; 00:00:56; mem_used: 74.8 MB; procmem: 391.1 MiB
[======>----] 60/100 eta:38s; 00:00:57; mem_used: 74.8 MB; procmem: 391.1 MiB
[======>----] 61/100 eta:38s; 00:00:58; mem_used: 74.8 MB; procmem: 391.2 MiB
[======>----] 62/100 eta:37s; 00:00:59; mem_used: 74.8 MB; procmem: 391.2 MiB
[======>----] 63/100 eta:36s; 00:01:00; mem_used: 74.8 MB; procmem: 391.2 MiB
[======>----] 64/100 eta:35s; 00:01:01; mem_used: 74.8 MB; procmem: 391.2 MiB
[======>----] 65/100 eta:34s; 00:01:02; mem_used: 74.8 MB; procmem: 391.2 MiB
[======>----] 66/100 eta:33s; 00:01:03; mem_used: 74.8 MB; procmem: 391.4 MiB
[======>----] 67/100 eta:32s; 00:01:04; mem_used: 74.8 MB; procmem: 391.4 MiB
[======>----] 68/100 eta:31s; 00:01:05; mem_used: 74.8 MB; procmem: 391.4 MiB
[=======>---] 69/100 eta:30s; 00:01:06; mem_used: 74.8 MB; procmem: 391.4 MiB
[=======>---] 70/100 eta:29s; 00:01:07; mem_used: 74.8 MB; procmem: 391.4 MiB
[=======>---] 71/100 eta:28s; 00:01:08; mem_used: 74.8 MB; procmem: 391.4 MiB
[=======>---] 72/100 eta:27s; 00:01:09; mem_used: 74.8 MB; procmem: 391.4 MiB
[=======>---] 73/100 eta:26s; 00:01:10; mem_used: 74.8 MB; procmem: 391.4 MiB
[=======>---] 74/100 eta:25s; 00:01:11; mem_used: 74.8 MB; procmem: 391.4 MiB
[=======>---] 75/100 eta:24s; 00:01:12; mem_used: 74.8 MB; procmem: 391.4 MiB
[=======>---] 76/100 eta:23s; 00:01:13; mem_used: 74.8 MB; procmem: 391.4 MiB
[=======>---] 77/100 eta:22s; 00:01:14; mem_used: 74.8 MB; procmem: 391.4 MiB
[========>--] 78/100 eta:21s; 00:01:15; mem_used: 74.8 MB; procmem: 391.4 MiB
[========>--] 79/100 eta:20s; 00:01:16; mem_used: 74.8 MB; procmem: 391.4 MiB
[========>--] 80/100 eta:19s; 00:01:17; mem_used: 74.8 MB; procmem: 391.4 MiB
[========>--] 81/100 eta:18s; 00:01:18; mem_used: 74.8 MB; procmem: 391.4 MiB
[========>--] 82/100 eta:17s; 00:01:19; mem_used: 74.8 MB; procmem: 391.4 MiB
[========>--] 83/100 eta:16s; 00:01:20; mem_used: 74.8 MB; procmem: 391.4 MiB
[========>--] 84/100 eta:16s; 00:01:21; mem_used: 74.8 MB; procmem: 391.4 MiB
[========>--] 85/100 eta:15s; 00:01:22; mem_used: 74.8 MB; procmem: 391.4 MiB
[========>--] 86/100 eta:14s; 00:01:23; mem_used: 74.8 MB; procmem: 391.4 MiB
[=========>-] 87/100 eta:13s; 00:01:24; mem_used: 74.8 MB; procmem: 391.4 MiB
[=========>-] 88/100 eta:12s; 00:01:25; mem_used: 74.8 MB; procmem: 391.4 MiB
[=========>-] 89/100 eta:11s; 00:01:26; mem_used: 74.8 MB; procmem: 391.4 MiB
[=========>-] 90/100 eta:10s; 00:01:27; mem_used: 74.8 MB; procmem: 391.4 MiB
[===========>-] 91/100 eta: 9s; 00:01:28; mem_used: 74.8 MB; procmem: 392 MiB
[===========>-] 92/100 eta: 8s; 00:01:29; mem_used: 74.8 MB; procmem: 392 MiB
[===========>-] 93/100 eta: 7s; 00:01:30; mem_used: 74.8 MB; procmem: 392 MiB
[===========>-] 94/100 eta: 6s; 00:01:31; mem_used: 74.8 MB; procmem: 392 MiB
[===========>-] 95/100 eta: 5s; 00:01:32; mem_used: 74.8 MB; procmem: 392 MiB
[===========>-] 96/100 eta: 4s; 00:01:33; mem_used: 74.8 MB; procmem: 392 MiB
[============>] 97/100 eta: 3s; 00:01:34; mem_used: 74.8 MB; procmem: 392 MiB
[============>] 98/100 eta: 2s; 00:01:35; mem_used: 74.8 MB; procmem: 392 MiB
[==========>] 99/100 eta: 1s; 00:01:36; mem_used: 74.8 MB; procmem: 392.2 MiB
[==========] 100/100 eta: 0s; 00:01:37; mem_used: 74.8 MB; procmem: 392.2 MiB

Stopping plumber API
...sleeping...
Generate Image
Parsed with column specification:
cols(
  route = col_character(),
  row = col_double(),
  mem_used = col_character(),
  procmem = col_character(),
  time = col_double()
)
mem_test: 

@wch
Copy link
Collaborator

wch commented Oct 9, 2019

A little more context: the pryr::mem_used() function reports the amount of memory consumed by R objects. The memuse::Sys.procmem() function reports how much memory is used by the process, according to the operating system.

We found that the amount of memory reported by pryr::mem_used() does not increase, but the memory reported by memuse::Sys.procmem()does increase. This means that the increase is due to C-level memory use. The question then is, is the increase in memory usage due to some sort of cache/buffers, or is it a memory leak?

We don't think it's a memory leak for a couple of reasons. First, the memory use appears to be asymptotic. Secondly, the memory use increase even if plumber isn't involved. If you repeatedly call do.call(rbind, replicate(10000, mtcars, simplify = F)) from the R prompt, the memory usage also increases asymptotically.

So it seems that the increase in memory usage is probably due to some sort of cache or buffers. I don't know enough about R's internals to say exactly what it is, though.

@LukasK13
Copy link
Author

I was able to reproduce this error using a basic R function to prove that it's not a problem for plumber:

test <- function(n = 10000) {
  dump = do.call(dplyr::rbind, replicate(n, mtcars, simplify = F))
  return()
}

Sys.sleep(5)
test()
Sys.sleep(5)
gc()

In the beginning, the R process allocated 35 MB RAM. After the first call of test(), the memory usage increased to 158 MB and dropped to 111 MB after calling gc(). So there is still a difference of 76 MB not beeing released.

Normally this wouldn't be much of a problem for a R script running once in a while. But as plumber ususally ist up 24/7 this leads to a huge memory leak. Should we report this to the developers of R?

In my use case, I am deploying plumber in a docker container (replication factor: 15) using HAProxy as load balancer. If large datasets are requested one after another, this causes the memory usage of each container to grow to significant sizes making it impossible to host on ordinary machines. The only solution I found was restarting the container.
Do you see any solution for a programmatic restart of plumber as a temporary fix? I was thinking about some postrequesthook or any other possibility.

Thank you for your help.

@schloerke
Copy link
Collaborator

Adding reprex output...

test_mem <- function(n = 100) {
  # generate data
  ignore <- do.call(rbind, replicate(n, ggplot2::diamonds, simplify = F))
  return()
}
print_mem <- function() {
  withAutoprint({
    gc()
    pryr::mem_used()
    memuse::Sys.procmem()
  })
}

print_mem()
#> > gc()
#>          used (Mb) gc trigger (Mb) limit (Mb) max used (Mb)
#> Ncells 476833 25.5    1030405 55.1         NA   663948 35.5
#> Vcells 887935  6.8    8388608 64.0      32768  1822016 14.0
#> > pryr::mem_used()
#> Registered S3 method overwritten by 'pryr':
#>   method      from
#>   print.bytes Rcpp
#> 34.2 MB
#> > memuse::Sys.procmem()
#> Size:  85.660 MiB

test_mem()
#> NULL
print_mem()
#> > gc()
#>           used (Mb) gc trigger  (Mb) limit (Mb) max used  (Mb)
#> Ncells  689509 36.9    1288835  68.9         NA  1030405  55.1
#> Vcells 1667893 12.8   76694957 585.2      32768 94968494 724.6
#> > pryr::mem_used()
#> 52 MB
#> > memuse::Sys.procmem()
#> Size:  2.477 GiB

test_mem()
#> NULL
print_mem()
#> > gc()
#>           used (Mb) gc trigger  (Mb) limit (Mb) max used  (Mb)
#> Ncells  690815 36.9    1288835  68.9         NA  1030405  55.1
#> Vcells 1670977 12.8   68087749 519.5      32768 94968494 724.6
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.164 GiB

Created on 2019-10-10 by the reprex package (v0.3.0)

@shrektan
Copy link
Contributor

shrektan commented Oct 10, 2019

@schloerke I can't reproduce your code on Mac. Do you use Mac as well? I've run the code several times. The first time, the total memory used increases by about 50 MB. The other runs show no increases in memory use at all (yeah, maybe for one time increase 150MB but reduced in the later runs).

Is it possible even if R has told the system "I have released some memory. When you need it please come and take it back" but the system currently has plenty of memories so it doesn't ask R to return that part of memory back?

@schloerke
Copy link
Collaborator

@shrektan I am on Mac as well. I'm able to reproduce your situation as well. I've found that after a certain threshold, the memory is not reclaimed by the OS.

Is it possible the OS wont reclaim memory that has been released?

Yes. I believe this is what we are seeing.

Also... Linux does not reclaim memory from a process. Docker is running linux. Therefore once the memory is obtained by the R process, it'll never leave.

I do not know why the already obtained memory is not being repurposed, causing the R process to balloon in memory usage.😞

Funny website about linux memory

Reclaim <= 1 GB, but fails to reclaim 2.5 GB
print_mem <- function() {
  withAutoprint({
    gc()
    pryr::mem_used()
    memuse::Sys.procmem()
  })
}
print_mem()
#> > gc()
#>          used (Mb) gc trigger (Mb) limit (Mb) max used (Mb)
#> Ncells 476978 25.5    1030820 55.1         NA   663948 35.5
#> Vcells 888952  6.8    8388608 64.0      32768  1821939 14.0
#> > pryr::mem_used()
#> Registered S3 method overwritten by 'pryr':
#>   method      from
#>   print.bytes Rcpp
#> 34.2 MB
#> > memuse::Sys.procmem()
#> Size:  89.531 MiB
x <- rnorm(1e8)
print_mem()
#> > gc()
#>             used  (Mb) gc trigger   (Mb) limit (Mb)  max used  (Mb)
#> Ncells    579261  31.0    1030820   55.1         NA    725551  38.8
#> Vcells 101089962 771.3  147978526 1129.0      32768 101529869 774.7
#> > pryr::mem_used()
#> 841 MB
#> > memuse::Sys.procmem()
#> Size:  856.555 MiB
# ~850mb. Great!
rm(x)
print_mem()
#> > gc()
#>           used (Mb) gc trigger  (Mb) limit (Mb)  max used  (Mb)
#> Ncells  579291 31.0    1030820  55.1         NA    725551  38.8
#> Vcells 1090032  8.4  118382821 903.2      32768 101529869 774.7
#> > pryr::mem_used()
#> 41.2 MB
#> > memuse::Sys.procmem()
#> Size:  93.613 MiB
# ~90mb. Great!
x <- rnorm(1e8)
# ~ 1 GB used
print_mem()
#> > gc()
#>             used  (Mb) gc trigger   (Mb) limit (Mb)  max used  (Mb)
#> Ncells    579313  31.0    1030820   55.1         NA    725551  38.8
#> Vcells 101090068 771.3  148161554 1130.4      32768 101529869 774.7
#> > pryr::mem_used()
#> 841 MB
#> > memuse::Sys.procmem()
#> Size:  856.574 MiB
# ~850mb. Great!
rm(x)
print_mem()
#> > gc()
#>           used (Mb) gc trigger  (Mb) limit (Mb)  max used  (Mb)
#> Ncells  579343 31.0    1030820  55.1         NA    725551  38.8
#> Vcells 1090138  8.4  118529244 904.4      32768 101529869 774.7
#> > pryr::mem_used()
#> 41.2 MB
#> > memuse::Sys.procmem()
#> Size:  93.648 MiB
# ~90mb. Great!
ignore <- do.call(rbind, replicate(100, ggplot2::diamonds, simplify = F))
print_mem()
#> > gc()
#>            used  (Mb) gc trigger  (Mb) limit (Mb)  max used  (Mb)
#> Ncells   689584  36.9    1291022  69.0         NA   1030820  55.1
#> Vcells 45506049 347.2   91110460 695.2      32768 101529869 774.7
#> > pryr::mem_used()
#> 403 MB
#> > memuse::Sys.procmem()
#> Size:  2.972 GiB
# ~3GB. Great!
rm(ignore)
print_mem()
#> > gc()
#>           used (Mb) gc trigger  (Mb) limit (Mb)  max used  (Mb)
#> Ncells  689588 36.9    1291022  69.0         NA   1030820  55.1
#> Vcells 1669033 12.8   72888368 556.1      32768 101529869 774.7
#> > pryr::mem_used()
#> 52 MB
#> > memuse::Sys.procmem()
#> Size:  2.724 GiB
# Not ~90mb. :-(
ignore <- do.call(rbind, replicate(100, ggplot2::diamonds, simplify = F))
print_mem()
#> > gc()
#>            used  (Mb) gc trigger  (Mb) limit (Mb)  max used  (Mb)
#> Ncells   689630  36.9    1291022  69.0         NA   1030820  55.1
#> Vcells 45506150 347.2   97159884 741.3      32768 101529869 774.7
#> > pryr::mem_used()
#> 403 MB
#> > memuse::Sys.procmem()
#> Size:  2.753 GiB
rm(ignore)
print_mem()
#> > gc()
#>           used (Mb) gc trigger  (Mb) limit (Mb)  max used  (Mb)
#> Ncells  689628 36.9    1291022  69.0         NA   1030820  55.1
#> Vcells 1669130 12.8   77727908 593.1      32768 101529869 774.7
#> > pryr::mem_used()
#> 52 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB
# Not ~90mb. :-(
for (i in 1:20) {
  print_mem()
}
#> > gc()
#>           used (Mb) gc trigger  (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691274 37.0    1291022  69.0         NA   1030820  55.1
#> Vcells 1672723 12.8   39796690 303.7      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger  (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691278 37.0    1291022  69.0         NA   1030820  55.1
#> Vcells 1672770 12.8   20375906 155.5      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691280 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1672787 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691283 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1672819 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691285 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1672843 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691287 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1672867 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691289 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1672891 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691291 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1672915 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691293 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1672939 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691295 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1672963 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691297 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1672987 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691299 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1673011 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691301 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1673035 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691303 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1673059 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691305 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1673083 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691307 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1673107 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691309 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1673131 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691311 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1673155 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691313 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1673179 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB 
#> > gc()
#>           used (Mb) gc trigger (Mb) limit (Mb)  max used  (Mb)
#> Ncells  691315 37.0    1291022 69.0         NA   1030820  55.1
#> Vcells 1673203 12.8   10432464 79.6      32768 101529869 774.7
#> > pryr::mem_used()
#> 52.1 MB
#> > memuse::Sys.procmem()
#> Size:  2.670 GiB

@shrektan
Copy link
Contributor

So it should be a more general issue about how OS manages the memory? As of Docker containers, There're options to constrain the memory usage of a Docker container and it may help in such cases.

@LukasK13
Copy link
Author

@shrektan I don't think limiting the memory for docker containers is the right way to go, as this disables the possibility to process large datasets.

@schloerke Can you further explain this for me?

Also... Linux does not reclaim memory from a process. Docker is running linux. Therefore once the memory is obtained by the R process, it'll never leave.

@shrektan
Copy link
Contributor

Well, you can set soft limits on it which will allow large datasets while may does the trick.

@dselivanov
Copy link

dselivanov commented Oct 13, 2019

Hi here. It looks like the issue is related to how glibc manages memory. And this is usually linux specific. More details here. Also I've reported this to r-bugzilla some time ago.

I would appreciate if some of you guys (especially @wch as you are very experienced in r-internals) can review my bug report and confirm it to r-core (as such things were recently requested in r-developer blog)

As a solution I recommend to switch to another implementation of malloc (such as jemalloc). This is exactly what we do in RestRserve:

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    libssl-dev libjemalloc-dev


ENV LD_PRELOAD /usr/lib/x86_64-linux-gnu/libjemalloc.so

@LukasK13
Copy link
Author

Wow this actually fixes the bug.
Thank you for looking into this and sharing the information. I would definitely consider this a bug in R-core! How can I help you in getting this fixed (I don't have an bugzilla account)?

@dselivanov
Copy link

dselivanov commented Oct 17, 2019

How can I help you in getting this fixed (I don't have an bugzilla account)

@LukasK13 Could you please create one and drop a comment in the issue?

@wch
Copy link
Collaborator

wch commented Oct 21, 2019

@dselivanov I think that you understand this domain better than I do -- I don't feel that I would be able to help here. Have you also tried asking about the memory issue on the r-devel mailing list?

@dselivanov
Copy link

Yes, I've opened bugzilla report after discussion on r devel. Links to r devel threads are in the ticket.

@schloerke schloerke added difficulty: intermediate Enterprising community members could help help wanted Solution is well-specified enough that any community member could fix out of focus Maintainers will not fix bug, but the issue should remain open until a resolution is found. difficulty: advanced Best for maintainers to address labels Oct 22, 2019
@LukasK13
Copy link
Author

@dselivanov how can I create a bugzilla account? I can't find a page for signing up.

@dselivanov
Copy link

@LukasK13

If you do not already have a bugzilla account send an e-mail (from the address you want to use as your login) to bug-report-request@r-project.org briefly explaining why, and a volunteer will add you to R’s Bugzilla members.

@atheriel
Copy link
Contributor

The topic of this issue has wandered a little, but on the subject of experimenting with R memory usage it might also be worth investigating the MALLOC_ARENA_MAX environment variable, which seems to improve memory fragmentation with certain kinds of Ruby programs.

@dselivanov
Copy link

@atheriel I think I've tried all those environment variables at some point. No one of them seem had any effect.

@schloerke schloerke mentioned this issue Nov 17, 2023
@schloerke
Copy link
Collaborator

Closing this issue in favor of solution provided by @dselivanov in #496 (comment)

It seems really fair that the standard memory leak is due to a inefficient malloc linux library. Changing the library had good success according to the comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
difficulty: advanced Best for maintainers to address difficulty: intermediate Enterprising community members could help help wanted Solution is well-specified enough that any community member could fix out of focus Maintainers will not fix bug, but the issue should remain open until a resolution is found.
Projects
None yet
Development

No branches or pull requests

6 participants