1

I get cumulating memory using the following code. Every time I switch between the action button 1 and 2 the used memory increases.

library(ggplot2)
library(shiny)
library(lobstr)

ui <- navbarPage("Test",fluidPage(fluidRow(
                     column(width = 1, actionButton("action_input_1", label = "1")), 
                     column(width = 1, actionButton("action_input_2", label = "2")),
                     column(width = 10, plotOutput("plot", width = 1400, height = 800)))))

server <- function(input, output) {
  # 1
  observeEvent(input$action_input_1, {
    output$plot <- renderPlot({
      plot(rnorm(100))
    })
    print(cat(paste0("mem used 1: ", capture.output(print(mem_used())),"\n")))
  })

  # 2
  observeEvent(input$action_input_2, {
    output$plot <- renderPlot({
      plot(rnorm(1000))
    })
    print(cat(paste0("mem used 2: ", capture.output(print(mem_used())),"\n")))
  })
}
shinyApp(ui, server)

Due to a suggestion in this post, I have tried not to use observeEvent. Here is the server function:

server <- function(input, output) {
  # 1
  output$plot <- renderPlot({
    input$action_input_1
    plot(rnorm(100))
    print(cat(paste0("mem used 1: ", capture.output(print(mem_used())),"\n")))
  })

  # 2
  output$plot <- renderPlot({
    input$action_input_2
    plot(rnorm(1000))
    print(cat(paste0("mem used 2: ", capture.output(print(mem_used())),"\n")))
  })
}

Here the memory does not increase, but only the second action button (=the last block of code?) is working. Is there a solution to prevent memory leak and get both buttons working?

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
DerDressing
  • 315
  • 1
  • 4
  • 19

1 Answers1

0

How about using reactiveVal :

reactiveData <- reactiveVal(NULL)
observeEvent(input$action_input_1, reactiveData(rnorm(100)))
observeEvent(input$action_input_2, reactiveData(rnorm(1000)))
output$plot <- renderPlot(plot(reactiveData()))

Reactive values have a little different syntax:

reactiveData <- reactiveValues(rnorm = NULL, bool_val = NULL) 

observeEvent(input$action_input_1,  {# reactiveData(rnorm(100), bool_val <- TRUE)) 
   reactiveData$rnorm <- rnorm(100)
   reactiveData$bool_val <- TRUE
})

observeEvent(input$action_input_2, { #reactiveData(rnorm(1000), bool_val <- FALSE)) 
  reactiveData$rnorm <- rnorm(1000)
  reactiveData$bool_val <-  FALSE
})

output$plot <- renderPlot(plot(reactiveData$rnorm))

Though your variables are changing in concert, so you could technically still use reactiveVal

reactiveData <- reactiveVal(list(rnorm = NULL, bool_val = NULL)) 

observeEvent(input$action_input_1, reactiveData(list(rnorm = 100, bool_val = TRUE)))

observeEvent(input$action_input_2, reactiveData(list(rnorm = 1000, bool_val = FALSE)))

output$plot <- renderPlot(plot(reactiveData()$rnorm))
SmokeyShakers
  • 3,372
  • 1
  • 7
  • 18
  • Note that this uses `observeEvent` but does not nest a `renderPlot`, which, I believe, is what causes the memory leak. – SmokeyShakers Dec 11 '19 at 15:13
  • Thanks, this works fine for the example, but not for my use case. Actually I want to pass more than one argument to reactiveData in the first instance. I think I have to use reactiveValues then, but it is not working. Can you please check this code: `reactiveData <- reactiveValues(rnorm = NULL, bool_val = NULL) observeEvent(input$action_input_1, reactiveData(rnorm(100), bool_val <- TRUE)) observeEvent(input$action_input_2, reactiveData(rnorm(1000), bool_val <- FALSE)) output$plot <- renderPlot(plot(reactiveData()))` – DerDressing Dec 12 '19 at 08:20
  • You're close. Updated my answer above. – SmokeyShakers Dec 12 '19 at 12:42
  • Great, it's working. You have answered my question. But I ran into another problem: If I use 'observe' instead of 'observeEvent' (because the reactiveData updates automatically from a file) I have still increasing memory while rendering a new plot. – DerDressing Dec 16 '19 at 07:34
  • I also tried `rm(list = ls())`, `gc(reset = TRUE)` and `gc()` but it seems to have no effect. – DerDressing Dec 16 '19 at 07:52
  • I'm not sure I understand exactly what you're doing now. Are your action buttons meant to trigger the file read? Can you post the code? – SmokeyShakers Dec 16 '19 at 13:32
  • I am using [this](https://shiny.rstudio.com/reference/shiny/1.0.3/reactivePoll.html) function (here: `data()`) to check, if there is new data in a folder. If yes: update the plot. The code is as follows: `observe(reactiveData$d <- data(), bool_val = FALSE)` – DerDressing Dec 18 '19 at 10:14
  • `observe(reactiveData$d <- data(), bool_val = FALSE)` isn't right. it should cause an `unused argument` error. Only one expression is passed to `observe`. – SmokeyShakers Dec 18 '19 at 13:58
  • I'm sorry, I forgot curly braces and remove the comma: `observe({reactiveData$d <- data() bool_val = FALSE})` – DerDressing Dec 19 '19 at 07:39
  • Ok, so `bool_val = FALSE` doesn't seem to be doing anything. The `bool_val` variable is local to the expression within `observe`. Ignoring that, try `observeEvent(data(), { reactiveData$d <- data() })`. You only want the expression to be triggered when `data()` changes, but your '`observe` is observing changes to `data()` and to `reactiveData$d`. – SmokeyShakers Dec 19 '19 at 14:05
  • Sorry for the late response. Your proposal is basically working (no error), but does not prevent memory leak in my case. In the meantime I have build a workaround using [this](https://stackoverflow.com/questions/25062422/restart-shiny-session). Actually this is not really satisfying but a pragmatic solution in my case. Thank you for all! – DerDressing Jan 07 '20 at 15:04