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

Consider reducing garbage when animating Path shapes

XMLWordPrintable

    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      OS: window11
      java verison: 17

      A DESCRIPTION OF THE PROBLEM :
      setRotate() causes memory to spike
      heap_dump.hprof: <LINK>
      <LINK>



      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      note TODO


      ---------- BEGIN SOURCE ----------

      import javafx.animation.AnimationTimer;
      import javafx.application.Application;
      import javafx.geometry.Pos;
      import javafx.scene.Scene;
      import javafx.scene.layout.BorderPane;
      import javafx.scene.layout.HBox;
      import javafx.scene.layout.Pane;
      import javafx.scene.paint.Color;
      import javafx.scene.shape.SVGPath;
      import javafx.scene.text.Font;
      import javafx.scene.text.Text;
      import javafx.stage.Stage;
      import javafx.stage.StageStyle;

      import java.util.ArrayList;
      import java.util.List;
      import java.util.function.Supplier;


      public class AnimationTimerApp extends Application {

          private final BorderPane root = new BorderPane();

          private final Text fpsText = new Text("FPS:");

          private final Text frameRateText = new Text();

          private final Supplier<SVGPath> svgPathSupplier = () -> {
              SVGPath svgPath = new SVGPath();
              svgPath.setContent("""
                  M15,0l-0.9,1.5v31.7l0.9,1.5l0.9-1.5V1.5L15,0z M15,7.5l-3.5-2.3V3.5L15,5.8V7.5z M15,11l-4.6-2.9V6.4L15,9.3
                      V11z M15,7.5l3.5-2.3V3.5L15,5.8V7.5z M15,11l4.6-2.9V6.4L15,9.3V11z M15,27.1l-3.5,2.3v1.7l3.5-2.3V27.1z M15,23.7l-4.6,2.9v1.7
                      l4.6-2.9V23.7z M15,27.1l3.5,2.3v1.7L15,28.8V27.1z M15,23.7l4.6,2.9v1.7L15,25.4V23.7z M0,26h1.7l27.4-15.8L30,8.7h-1.7L0.9,24.5
                      L0,26z M6.5,22.2l-0.3,4.1l-1.5,0.9L5,23.1L6.5,22.2z M9.5,20.5l-0.2,5.4l-1.5,0.9L8,21.4L9.5,20.5z M6.5,22.2l-3.7-1.8l-1.5,0.9
                      L5,23.1L6.5,22.2z M9.5,20.5L4.7,18l-1.5,0.9L8,21.4L9.5,20.5z M23.5,12.4l3.7,1.8l1.5-0.9L25,11.6L23.5,12.4z M20.5,14.2l4.8,2.6
                      l1.5-0.9L22,13.3L20.5,14.2z M23.5,12.4l0.3-4.1l1.5-0.9L25,11.6L23.5,12.4z M20.5,14.2l0.2-5.4l1.5-0.9L22,13.3L20.5,14.2z M30,26
                      h-1.7L0.9,10.2L0,8.7h1.7l27.4,15.8L30,26z M23.5,22.2l0.3,4.1l1.5,0.9L25,23.1L23.5,22.2z M20.5,20.5l0.2,5.4l1.5,0.9L22,21.4
                      L20.5,20.5z M23.5,22.2l3.7-1.8l1.5,0.9L25,23.1L23.5,22.2z M20.5,20.5l4.8-2.5l1.5,0.9L22,21.4L20.5,20.5z M6.5,12.4l-3.7,1.8
                      l-1.5-0.9L5,11.6L6.5,12.4z M9.5,14.2l-4.8,2.6l-1.5-0.9L8,13.3L9.5,14.2z M6.5,12.4L6.3,8.3L4.8,7.4L5,11.6L6.5,12.4z M9.5,14.2
                      L9.3,8.8L7.8,7.9L8,13.3L9.5,14.2z M15,22.8l-4.7-2.7v-5.4l4.7-2.7l4.7,2.7V20L15,22.8z M11.7,19.2l3.3,1.9l3.3-1.9v-3.7L15,13.6
                      l-3.3,1.9V19.2z
                  """);
              svgPath.setFill(Color.SNOW);
              return svgPath;
          };

          private final int svgPathCapacity = 500;
          private final List<SVGPath> svgPathList = new ArrayList<>(svgPathCapacity);

          private final AnimationTimer animationTimer = new AnimationTimer() {

              // 上次计算FPS的时间戳
              private long lastTime;

              // 处理次数
              private int handleCount;

              @Override
              public void handle(long now) {
                  // 计算FPS
                  computeFPS(now);
                  double rootHeight = root.getHeight();
                  double width = root.getWidth() - 30.0;
                  svgPathList.forEach(svgPath -> {
                      double translateY = svgPath.getTranslateY();
                      // 重新设置初始值
                      if (translateY >= rootHeight) {
                          svgPath.setRotate(0.0);
                          svgPath.setTranslateX(Math.random() * width);
                          svgPath.setTranslateY(0.0);
                          double scale = Math.random() + 0.1;
                          svgPath.setScaleX(scale);
                          svgPath.setScaleY(scale);
                          return;
                      }
                      svgPath.setTranslateY(translateY + 1.0);
                      // TODO: 这里好像存在内存飙升问题??
                      svgPath.setRotate(svgPath.getRotate() + 1.0);
                  });
              }

              private void computeFPS(long now) {
                  // 距离上一帧经过的时间
                  long elapsedTime = now - lastTime;
                  long seconds = elapsedTime / 1_000_000_000;
                  // 经过了1秒
                  if (seconds >= 1L) {
                      // 设置FPS(处理数 / 经过时间)
                      frameRateText.setText(String.valueOf(handleCount / seconds));
                      handleCount = 0;
                      // 保存上一秒时间戳
                      lastTime = now;
                  }
                  handleCount++;
              }

          };


          public static void main(String[] args) {
              Application.launch(args);
          }

          @Override
          public void init() {
              fpsLayout();
          }

          private void fpsLayout() {
              fpsText.setFont(Font.font(30.0));
              fpsText.setFill(Color.WHITE);
              frameRateText.setFont(Font.font(30.0));
              frameRateText.setFill(Color.WHITE);
              HBox fpsHBox = new HBox(10.0, fpsText, frameRateText);
              fpsHBox.setMaxSize(0.0, 0.0);
              BorderPane.setAlignment(fpsHBox, Pos.TOP_RIGHT);
              root.setTop(fpsHBox);
          }


          public void start(Stage primaryStage) {
              primaryStage.setTitle(getClass().getSimpleName());
              // 透明窗体
              primaryStage.initStyle(StageStyle.TRANSPARENT);
              // 设置最大化
              primaryStage.setMaximized(true);
              // 位于顶层
              primaryStage.setAlwaysOnTop(true);
              primaryStage.setScene(new Scene(root,null));
              primaryStage.show();

              double width = root.getWidth() - 30.0;
              double height = root.getHeight();
              for (int i = 0; i < svgPathCapacity; i++) {
                  SVGPath svgPath = svgPathSupplier.get();
                  svgPath.setTranslateX(Math.random() * width);
                  svgPath.setTranslateY(Math.random() * height);
                  double scale = Math.random() + 0.1;
                  svgPath.setScaleX(scale);
                  svgPath.setScaleY(scale);
                  svgPathList.add(svgPath);
              }
              root.setCenter(new Pane(svgPathList.toArray(new SVGPath[0])));
              animationTimer.start();
          }
      }

      ---------- END SOURCE ----------

      FREQUENCY : always


        1. AnimationTimerApp.java
          4 kB
          Praveen Narayanaswamy
        2. Capture.PNG
          238 kB
          Praveen Narayanaswamy
        3. heap.png
          148 kB
          Praveen Narayanaswamy
        4. Picture1.png
          288 kB
          Praveen Narayanaswamy
        5. Picture2.png
          65 kB
          Praveen Narayanaswamy

            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: