JDK-8095722 : Win: Huge Memory Consumption for Transparent Stage
  • Type: Bug
  • Component: javafx
  • Sub-Component: graphics
  • Affected Version: 8
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2013-11-24
  • Updated: 2015-06-12
  • Resolved: 2014-11-01
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8u40Fixed
Related Reports
Relates :  
Relates :  
Description
When executing the test below the memory consumption in the Task Manager grows up to 2GB within seconds on my test system - the issue does not occur when the stage style is changed from TRANSPARENT to UNDECORATED.

    public class TransparentStageMemoryIssueTest extends Application  
    {  
      public static void main(String[] args)  
      {  
        Application.launch(args);  
      }  
      @Override  
      public void start(Stage stage)  
      {  
        System.err.println(System.getProperty("javafx.runtime.version"));  
        //stage.initStyle(StageStyle.UNDECORATED);  
        stage.initStyle(StageStyle.TRANSPARENT);  
        final BorderPane root = new BorderPane();  
        root.setStyle("-fx-background-color:#808080;-fx-background-radius:30;-fx-border-radius:30;-fx-border-width:14;-fx-border-color:blue;");  
        Scene scene = new Scene(root, 800, 600);  
        stage.setScene(scene);  
        stage.setX(10);  
        stage.setY(10);  
        stage.show();  
        new Thread()  
        {  
          public void run()  
          {  
            for (int i = 0; i < 1000; i++)  
            {  
              Platform.runLater(new Runnable()  
              {  
                @Override  
                public void run()  
                {  
                  int minSize = 500;  
                  int maxSize = 1000;  
                  int w = minSize + new Random().nextInt(maxSize - minSize);  
                  int h = minSize + new Random().nextInt(maxSize - minSize);  
                  Window win = root.getScene().getWindow();  
                  win.setWidth(w);  
                  win.setHeight(h);  
                }  
              });  
              try  
              {  
                sleep(50);  
              }  
              catch (InterruptedException e)  
              {  
                e.printStackTrace();  
              }  
            }  
          };  
        }.start();  
      }  
    }  
Comments
Looks good to me, too.
01-11-2014

Fixed in the 8u-dev repo with the following changeset: changeset: 8310:4ca08590bb06 date: Fri Oct 31 18:57:32 2014 -0700 summary: Fix RT-34467: Huge memory consumption resizing transparent stage http://hg.openjdk.java.net/openjfx/8u-dev/rt/rev/4ca08590bb06
01-11-2014

+1 - great to see this old problem fixed.
01-11-2014

Building on the recent fixes for RT-38923 I modified that mechanism to reduce the number of reallocations of buffers. Webrev: http://cr.openjdk.java.net/~flar/RT-34467/webrev.00/
01-11-2014

This may be the same bug as RT-38923
30-10-2014

I've simply watching the used memory in the Windows TaskManager.
04-09-2014

This is very likely a Graphics issue in Quantum (UploadingPainter), so I am reassigning it to myself. We need to allocate buffers of memory for uploading pixels in the case of transparent windows, but there should never be more than two active buffers the size of the window allocated at any one time. How are you measuring the memory consumption? Are you just looking at the heap size of the Windows process or are you seeing that much memory actually in use?
04-09-2014

On Java8 b118 32Bit memory consumption is much less - between 50MB and 280MB.
06-12-2013

I'm on Win7 64-bit (two screens), when running Java8 b118 64Bit the memory consumption starts with around 120MB and takes around 20 seconds to grow up to 2GB - then is falls down back to 120MB and takes another 20 seconds to reach 2GB and so on. When there is less then 2GB available the exception below occurs after a while. java.lang.OutOfMemoryError: Direct buffer memory at java.nio.Bits.reserveMemory(Bits.java:658) at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123) at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311) at com.sun.prism.impl.BufferUtil.newByteBuffer(BufferUtil.java:94) at com.sun.prism.impl.BufferUtil.newIntBuffer(BufferUtil.java:125) at com.sun.javafx.tk.quantum.UploadingPainter.run(UploadingPainter.java:144) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:129) at java.lang.Thread.run(Thread.java:744)
06-12-2013

Could you please try 32-bit JVM and see if the issue is reproducible then?
06-12-2013

I'm running the original test case from the Description of this issue for, like, 20 minutes already, and the memory consumption for the Java process stays at around 120 MB fluctuating lower or higher from time to time. For how long should I run it to get an OOM, or otherwise see what you see? FWIW, I'm on Win 7 64-bit OS, running 32-bit Java (a latest development build of FX 8.)
05-12-2013

Wondering why the priority is set to Medium and fix version is 9? Because of this issue we are not able to create large non-rectangular windows with custom window decoration - the GC gets so busy that the application can't be used any longer.
05-12-2013

As it turned out the issue also occurs when the stage size isn't changed and only the content is modified. The example below demonstrates the behavior with a simple animation. When the stage size is set to 1800x1200 the memory consumption is about 300MB. When changing the stage size to 1900x1200 the memory consumption grows up to 2GB. To me it looks like a major issue. public class TransparentSceneMemoryIssueTest2 extends Application { private Timeline timeline; private AnimationTimer timer; private Integer i = 0; public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { System.err.println(System.getProperty("javafx.runtime.version")); //stage.initStyle(StageStyle.UNDECORATED); stage.initStyle(StageStyle.TRANSPARENT); StackPane root = new StackPane(); root.getChildren().add(createContent()); root.setStyle("-fx-background-color:#808080;-fx-background-radius:30;-fx-border-radius:30;-fx-border-width:14;-fx-border-color:blue;"); Scene scene = new Scene(root, 1900, 1200); stage.setScene(scene); scene.setFill(Color.TRANSPARENT); stage.setX(10); stage.setY(10); stage.show(); } private Parent createContent() { Group p = new Group(); final Circle circle = new Circle(25, Color.rgb(156, 216, 255)); //circle.setEffect(new Lighting()); circle.setEffect(new DropShadow(BlurType.THREE_PASS_BOX, Color.BLACK, 20, 0.25D, 0.0D, 0.0D)); final Text text = new Text(i.toString()); text.setStroke(Color.BLACK); final StackPane stack = new StackPane(); stack.getChildren().addAll(circle, text); stack.setLayoutX(30); stack.setLayoutY(30); stack.setStyle("-fx-background-color:#FF8080"); p.getChildren().add(stack); timeline = new Timeline(); timeline.setCycleCount(Timeline.INDEFINITE); timeline.setAutoReverse(true); timer = new AnimationTimer() { @Override public void handle(long l) { text.setText(i.toString()); i++; } }; KeyValue keyValueX = new KeyValue(stack.scaleXProperty(), 15); KeyValue keyValueY = new KeyValue(stack.scaleYProperty(), 15); Duration duration = Duration.millis(2000); EventHandler onFinished = new EventHandler<ActionEvent>() { public void handle(ActionEvent t) { i = 0; } }; KeyFrame keyFrame = new KeyFrame(duration, onFinished, keyValueX, keyValueY); timeline.getKeyFrames().add(keyFrame); timeline.play(); timer.start(); TranslateTransition translateTransition = new TranslateTransition(Duration.millis(2000), circle); translateTransition.setFromX(0); translateTransition.setToX(250); translateTransition.setCycleCount(Timeline.INDEFINITE); translateTransition.setAutoReverse(true); return p; } }
25-11-2013

This means the transparent mode can hardly be used for creating a non-native (i.e.non-rectangular) frame decoration for resizable windows.
25-11-2013

On WIndows we use UploadingPainter for transparent stages because the only way to render transparent windows on Windows is to pass ARGB bitmaps to the native system (through the ::UpdateLayeredWindow() API). Hence, if you randomly resize the window may times in a row, a lot of intermediate bitmaps get created for each size. GC takes some time to clean them up, hence the increase in memory consumption is expected in this case. To workaround this, try to minimize the size of transparent stages. Also, consider not changing their size too very often. We will take a look at this problem for FX 9 and see if we can enhance the current behavior somehow. I wound't expect dramatic changes though, because of the native system limitation imposed by the WinAPI that is used to implement transparent windows.
25-11-2013

Not reproducible on Linux. Maybe something in the windows glass implementation? Assigning to Glass team to investigate.
25-11-2013