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.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 ----------