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
        2. Capture.PNG
          Capture.PNG
          238 kB
        3. heap.png
          heap.png
          148 kB
        4. Picture1.png
          Picture1.png
          288 kB
        5. Picture2.png
          Picture2.png
          65 kB

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

              Created:
              Updated: