Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8196555

Memory Leak when running a Timer with fixed rate and changing a button's Effect to show a DropShadow.

XMLWordPrintable

    • generic
    • generic

      FULL PRODUCT VERSION :
      1.8.0_144

      ADDITIONAL OS VERSION INFORMATION :
      Darwin 17.3.0 Darwin Kernel Version 17.3.0; root:xnu-4570.31.3~1/RELEASE_X86_64 x86_64

      Microsoft Windows [Version 6.3.9600]

      A DESCRIPTION OF THE PROBLEM :
      Memory usage increases non-stop when using a Timer and, inside the TimerTask, I change a button's Effect to show a DropShadow. The problem is worse when every time I call button.setEffect() I pass in 'new DropShadow()'. It consumes memory at a faster rate. If I do .setEffect() with only 1 object created beforehand, memory increases at a lower rate.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the program and monitor the memory usage for this app. It will increase while time passes.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Memory could increase, but it would decrease again after Garbage Collector runs.
      ACTUAL -
      Memory allocation is higher and keeps increasing over time and never decreases. (Consumption is higher on Mac)

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package blinkingmemoryleak;

      import java.util.Timer;
      import java.util.TimerTask;
      import javafx.application.Application;
      import javafx.event.ActionEvent;
      import javafx.event.EventHandler;
      import javafx.scene.Scene;
      import javafx.scene.control.Button;
      import javafx.scene.effect.DropShadow;
      import javafx.scene.effect.Effect;
      import javafx.scene.image.Image;
      import javafx.scene.image.ImageView;
      import javafx.scene.layout.StackPane;
      import javafx.stage.Stage;
      import javafx.stage.WindowEvent;

      /**
       * Demonstrate a memory leak on macOS 10.13.2 and Windows 8.1 Pro (running
       * the same JDK [1.8.0_144]).
       * @author Melkis Espinal
       */
      public class BlinkingMemoryLeak extends Application
      {
          Timer timer;
          TimerTask timerTask;
          Button btn = new Button("Click To Stop Animation");
          DropShadow ds = new DropShadow();
          @Override
          public void start(Stage primaryStage)
          {
              primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>()
              {
                  @Override
                  public void handle(WindowEvent event)
                  {
                      if(timer != null)
                      {
                          timer.cancel();
                          primaryStage.close();
                          System.exit(0);
                      }
                  }
              });
              //add alarm.png image for the button icon
              //Image img = new Image(getClass().getResourceAsStream("alarm1.png"), 50, 50, true, true);
              //ImageView iv = new ImageView(img);
              //btn.setGraphic(iv);
              
              StackPane root = new StackPane();
              root.getChildren().add(btn);
              
              Scene scene = new Scene(root, 500, 500);
              
              primaryStage.setTitle("Blinking Memory Leak");
              primaryStage.setScene(scene);
              primaryStage.show();
              
              setupTimer();
          }
          
          /**
           * Sets up timer and button listener on action to start or stop the timer.
           */
          public void setupTimer()
          {
              timerTask = new TimerTask() {
                  @Override
                  public void run()
                  {
                      Effect effect = btn.getEffect();
                      if(effect == null)
                      {
                          btn.setEffect(ds);
                      }
                      else
                      {
                          btn.setEffect(null);
                      }
                      effect = null;
                  }
              };
              timer = new Timer();
              timer.scheduleAtFixedRate(timerTask, 0, 100);
              btn.setOnAction(new EventHandler<ActionEvent>()
              {
                  @Override
                  public void handle(ActionEvent event)
                  {
                      btn.setEffect(null);
                      if(timer != null)
                      {
                          timer.cancel();
                          timer = null;
                      }
                      if(timerTask != null)
                      {
                          timerTask.cancel();
                          timerTask = null;
                      }
                  }
              });
          }
          
          /**
           * @param args the command line arguments
           */
          public static void main(String[] args)
          {
              launch(args);
          }
      }
      ---------- END SOURCE ----------

        1. 8u40_jConsole.png
          77 kB
          Priyanka Mangal
        2. BlinkingMemoryLeak.java
          3 kB
          Priyanka Mangal

            arapte Ambarish Rapte
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated: