CPU使用时间轴使用JavaFX每30帧激活一次PNG

时间:2015-04-12 21:05:07

标签: java animation javafx timeline

我正在尝试使用JavaFX中的TimeLine来快速显示450个PNG文件,每80毫秒最好。我甚至不能在1.5秒内做到这一点。这些文件各约为60kb。在动画开始之前,文件被读取并存储在内存中

会发生什么:

GC每隔+ -30帧运行一次,动画完全停止

我尝试了什么:

  • 显示每张图片的SVGPath
  • SVGPath转换为PNG并在原始动画中显示
  • 将文件读入Image对象并存储在PriorityQueue中。使用不同的ImageView对象
  • 在屏幕上填充单个Image
  • 将文件读入不同的ImageView个对象,用setVisible(false)填充所有对象,然后在动画运行时我只设置一个setVisible(true)
  • 更改动画的创建方式,最后一个化身可以在这篇文章中看到
  • 将cycleCount更改为unlimited或将其设置为1,然后每次都启动TimeLine。实际上我需要它是1并且每次都启动TimeLine,因为在动画之前我需要做其他事情。这适用于我的3D打印机,因此打印机可能需要在显示图层之前和显示图层之后执行某些操作。用户可以配置
  • 我尝试更改VM选项(我有超过10GB的空闲内存):

    -Xms10680m -Xmx10680m -XX:PermSize=1256m -XX:MaxPermSize=1256m -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedOops -XX:NewSize=1200m -XX:MaxNewSize=1200m

- 升级虚拟机

下一步

我将尝试视口并查看是否仍然会激活CPU,因为它将是一个大对象,只是将视图移到它上面。希望它能解决问题

运行应用

我启动应用程序,加载模型,在开始动画之前,VM使用率为2.4GB,而不是指定的10GB。当我启动应用程序时,它将图像缓冲到队列中,内存为4.5GB,仍然不是10GB。当动画运行时,内存增加到5GB,实际上波动到低于5GB以上

Java版

java version" 1.8.0_40-ea" Java(TM)SE运行时环境(版本1.8.0_40-ea-b15) Java HotSpot(TM)64位服务器VM(版本25.40-b18,混合模式)

升级版Java

java版" 1.8.0_40" Java(TM)SE运行时环境(版本1.8.0_40-b26) Java HotSpot(TM)64位服务器VM(版本25.40-b25,混合模式)

现在它每40帧停止一次,而不是每30帧停止

GC日志

 CMS: abort preclean due to time 232.460: [CMS-concurrent-abortable-preclean: 1.017/97.038 secs] [Times: user=28.11 sys=2.54, real=97.04 secs] 
232.463: [GC (CMS Final Remark) [YG occupancy: 649460 K (1105920 K)]232.463: [Rescan (parallel) , 0.1360990 secs]232.599: [weak refs processing, 0.0000293 secs]232.599: [class unloading, 0.0278749 secs]232.627: [scrub symbol table, 0.0024514 secs]232.630: [scrub string table, 0.0006221 secs][1 CMS-remark: 1010091K(9707520K)] 1659552K(10813440K), 0.1735120 secs] [Times: user=0.66 sys=0.00, real=0.17 secs] 
232.637: [CMS-concurrent-sweep-start]
236.988: [GC (Allocation Failure) 236.988: [ParNew: 1105126K->122880K(1105920K), 0.5563841 secs] 2115195K->2064334K(10813440K), 0.5564532 secs] [Times: user=2.64 sys=0.66, real=0.56 secs] 
242.032: [CMS-concurrent-sweep: 0.760/9.395 secs] [Times: user=13.48 sys=1.01, real=9.39 secs] 
242.032: [CMS-concurrent-reset-start]
242.094: [CMS-concurrent-reset: 0.062/0.062 secs] [Times: user=0.09 sys=0.06, real=0.06 secs] 
246.489: [GC (Allocation Failure) 246.489: [ParNew: 1103611K->122880K(1105920K), 0.4099299 secs] 3045066K->2974070K(10813440K) icms_dc=6 , 0.4100021 secs] [Times: user=1.12 sys=1.36, real=0.41 secs] 
253.224: [GC (CMS Initial Mark) [1 CMS-initial-mark: 2851190K(9707520K)] 3454329K(10813440K), 0.0044382 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
253.229: [CMS-concurrent-mark-start]
255.071: [CMS-concurrent-mark: 1.842/1.843 secs] [Times: user=3.84 sys=0.02, real=1.84 secs] 
255.071: [CMS-concurrent-preclean-start]
255.103: [CMS-concurrent-preclean: 0.031/0.031 secs] [Times: user=0.03 sys=0.00, real=0.03 secs] 
255.103: [CMS-concurrent-abortable-preclean-start]
 CMS: abort preclean due to time 260.113: [CMS-concurrent-abortable-preclean: 1.737/5.011 secs] [Times: user=3.28 sys=0.05, real=5.01 secs] 
260.114: [GC (CMS Final Remark) [YG occupancy: 603138 K (1105920 K)]260.114: [Rescan (parallel) , 0.0107781 secs]260.125: [weak refs processing, 0.0000543 secs]260.125: [class unloading, 0.0321900 secs]260.157: [scrub symbol table, 0.0024284 secs]260.159: [scrub string table, 0.0005998 secs][1 CMS-remark: 2851190K(9707520K)] 3454329K(10813440K), 0.0517110 secs] [Times: user=0.09 sys=0.02, real=0.05 secs] 
260.166: [CMS-concurrent-sweep-start]
260.932: [CMS-concurrent-sweep: 0.767/0.767 secs] [Times: user=0.78 sys=0.02, real=0.77 secs] 
260.932: [CMS-concurrent-reset-start]
260.950: [CMS-concurrent-reset: 0.018/0.018 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
264.709: [Full GC (System.gc()) 264.709: [CMS: 2850762K->3328314K(9707520K), 6.1267248 secs] 3453901K->3328314K(10813440K), [Metaspace: 27214K->27214K(1073152K)] icms_dc=2 , 6.1282785 secs] [Times: user=5.93 sys=0.16, real=6.13 secs] 
270.838: [GC (CMS Initial Mark) [1 CMS-initial-mark: 3328314K(9707520K)] 3341357K(10813440K), 0.0008962 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
270.839: [CMS-concurrent-mark-start]
282.708: [Full GC (System.gc()) 282.708: [CMS284.474: [CMS-concurrent-mark: 1.765/13.635 secs] [Times: user=4.57 sys=0.13, real=13.63 secs] 
 (concurrent mode interrupted): 3328314K->3328357K(9707520K), 7.6842704 secs] 3364891K->3328357K(10813440K), [Metaspace: 27270K->27270K(1073152K)] icms_dc=7 , 7.6858220 secs] [Times: user=9.39 sys=0.01, real=7.69 secs] 
302.308: [Full GC (System.gc()) 302.308: [CMS: 3328357K->3328494K(9707520K), 6.0054401 secs] 3362268K->3328494K(10813440K), [Metaspace: 27306K->27306K(1073152K)] icms_dc=7 , 6.0070951 secs] [Times: user=5.98 sys=0.02, real=6.01 secs] 
308.316: [GC (CMS Initial Mark) [1 CMS-initial-mark: 3328494K(9707520K)] 3328494K(10813440K), 0.0008023 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
308.317: [CMS-concurrent-mark-start]
320.308: [Full GC (System.gc()) 320.308: [CMS322.084: [CMS-concurrent-mark: 1.777/13.768 secs] [Times: user=4.10 sys=0.13, real=13.77 secs] 
 (concurrent mode interrupted): 3328494K->3328612K(9707520K), 7.1761016 secs] 3374259K->3328612K(10813440K), [Metaspace: 27340K->27340K(1073152K)] icms_dc=7 , 7.1777096 secs] [Times: user=8.91 sys=0.02, real=7.18 secs] 
339.108: [Full GC (System.gc()) 339.108: [CMS: 3328612K->3328734K(9707520K), 4.7149083 secs] 3381859K->3328734K(10813440K), [Metaspace: 27356K->27356K(1073152K)] icms_dc=7 , 4.7166533 secs] [Times: user=4.71 sys=0.00, real=4.72 secs] 
343.825: [GC (CMS Initial Mark) [1 CMS-initial-mark: 3328734K(9707520K)] 3338934K(10813440K), 0.0005971 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
343.826: [CMS-concurrent-mark-start]
355.908: [Full GC (System.gc()) 355.908: [CMS357.692: [CMS-concurrent-mark: 1.785/13.866 secs] [Times: user=4.26 sys=0.11, real=13.87 secs] 
 (concurrent mode interrupted): 3328734K->3328845K(9707520K), 6.5141915 secs] 3395891K->3328845K(10813440K), [Metaspace: 27376K->27376K(1073152K)] icms_dc=7 , 6.5157445 secs] [Times: user=8.25 sys=0.03, real=6.52 secs] 
374.308: [Full GC (System.gc()) 374.308: [CMS: 3328845K->3328969K(9707520K), 5.1376448 secs] 3399645K->3328969K(10813440K), [Metaspace: 27393K->27393K(1073152K)] icms_dc=7 , 5.1391948 secs] [Times: user=5.13 sys=0.00, real=5.14 secs] 
379.447: [GC (CMS Initial Mark) [1 CMS-initial-mark: 3328969K(9707520K)] 3339169K(10813440K), 0.0006191 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
379.448: [CMS-concurrent-mark-start]
391.907: [Full GC (System.gc()) 391.907: [CMS393.678: [CMS-concurrent-mark: 1.772/14.231 secs] [Times: user=4.31 sys=0.14, real=14.23 secs] 
 (concurrent mode interrupted): 3328969K->3329043K(9707520K), 7.0341647 secs] 3407161K->3329043K(10813440K), [Metaspace: 27454K->27454K(1073152K)] icms_dc=7 , 7.0357178 secs] [Times: user=8.75 sys=0.05, real=7.04 secs] 
411.910: [Full GC (System.gc()) 411.910: [CMS: 3329043K->3329171K(9707520K), 5.7665632 secs] 3426534K->3329171K(10813440K), [Metaspace: 27477K->27477K(1073152K)] icms_dc=7 , 5.7681657 secs] [Times: user=5.77 sys=0.00, real=5.77 secs] 
417.678: [GC (CMS Initial Mark) [1 CMS-initial-mark: 3329171K(9707520K)] 3329171K(10813440K), 0.0008204 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
417.679: [CMS-concurrent-mark-start]

排队填充

我使用Executors填充队列

executorService = Executors.newFixedThreadPool(LAYER_PRODUCERS);
for (int i = -0; i < totalLayers; i++) {
    layerProducer = new LayerProducer(queueImage, i);
    executorService.submit(layerProducer);
}

等待队列填充然后开始动画

我等待线程填充队列然后我用Platform.runLater()启动动画,因为它需要在屏幕上运行Thread

new Thread() {
    @Override
    public void run() {
        try {
            while (true || executorService.isShutdown()) {
                Thread.sleep(1000);

                if (queueImage.size() >= (bufferSizeCalculated - 1)) {

                    break;
                }
            }

            Platform.runLater(() -> {
                runPrintThread();
            });
        } catch (InterruptedException ex) {
            Logger.getLogger(PrintingEngine.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}.start();

动画循环

private void configureTimeLineContinuousNoBuildPlateMoveAnimation(Profile profile) {
    timeLocation = 0;
    List<KeyFrame> list = new ArrayList<>();
    ObservableList<KeyFrame> observableList = FXCollections.observableList(list);

    //create first frame
    KeyFrame firstKeyFrame = new KeyFrame(Duration.millis(timeLocation), (ActionEvent t) -> {
        GizmoSlice gizmoSlice = queueImage.poll();
        ImageView currentImageView = gizmoSlice.getFilledImage();
        currentImageView.setVisible(true);
        previousImageView = currentImageView;
        printEngineCallback.updateLog("Display Layer " + gizmoSlice.getName());
    });

    observableList.add(firstKeyFrame);

    for (int i = 0; i < totalLayers; i++) {
        //create a keyframe for each layer
        KeyFrame keyFrame = new KeyFrame(Duration.millis(timeLocation = timeLocation + projectionTime), (ActionEvent t) -> {
            previousImageView.setVisible(false);

            GizmoSlice gizmoSlice = queueImage.poll();
            ImageView currentImageView = gizmoSlice.getFilledImage();
            currentImageView.setVisible(true);
            previousImageView = currentImageView;
            printEngineCallback.updateLog("Display Layer " + gizmoSlice.getName());
        });

        observableList.add(keyFrame);

    }

    engineTimeLine = TimelineBuilder.create()
            .cycleCount(1)
            .keyFrames(list)
            .autoReverse(false).build();
}

测试代码

我写了一个单独的应用程序执行此操作,CPU根本没有尖峰。所以代码可能很好,VM可能很好。不知道问题可能是什么。没有其他东西在后台运行,它只是一个大型的JavaFX客户端应用程序

package au.com.gizmo3dprinters;

import static au.com.gizmo3dprinters.Constants.GIZMO_SLICE;
import static au.com.gizmo3dprinters.Constants.TEMP_DIRECTORY;
import au.com.gizmo3dprinters.model.GizmoSlice;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.animation.TimelineBuilder;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.util.Duration;

/**
 *
 * @author kobus
 */
public class FXMLDocumentController implements Initializable {
    private static final int BUFFER_SIZE = 1; //larger number is a smaller buffer
    private static final int LAYER_PRODUCERS = 3; //larger is more memory and cpu power

    private int totalLayers;
    private PriorityQueue<GizmoSlice> queueImage;
    private int projectionTime;
    private Timeline engineTimeLine;

    @FXML
    private ImageView sliceImageView;

    @FXML
    private Label label;

    @FXML
    private void handleButtonAction(ActionEvent event) {
        Comparator<GizmoSlice> comparator = new GizmoSliceComparator();
        double bufferSizeCalculated = totalLayers / BUFFER_SIZE;
        queueImage = new PriorityQueue(Double.valueOf(bufferSizeCalculated).intValue(), comparator);
        String gizmoName = "noname_1428817659204.gizmo";

        ExecutorService executorService = Executors.newFixedThreadPool(LAYER_PRODUCERS);
        for (int i = -0; i < totalLayers; i++) {
            LayerProducer layerProducer = new LayerProducer(queueImage, i, gizmoName);
            executorService.submit(layerProducer);
        }
        executorService.shutdown();
        try {
            executorService.awaitTermination(3, TimeUnit.SECONDS);
        } catch (InterruptedException ex) {
            Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
        }

        configureTimeLineContinuousNoBuildPlateMoveAnimation();
        engineTimeLine.playFromStart();
    }


    private void configureTimeLineContinuousNoBuildPlateMoveAnimation() {
        long timeLocation = 0;
        List<KeyFrame> list = new ArrayList<>();
        ObservableList<KeyFrame> observableList = FXCollections.observableList(list);

        //create first frame
        KeyFrame firstKeyFrame = new KeyFrame(Duration.millis(timeLocation), (ActionEvent t) -> {
            GizmoSlice gizmoSlice = queueImage.poll();
            System.out.println("display layer " + gizmoSlice.getLayer());
            Image currentImage = gizmoSlice.getFilledImage();
            sliceImageView.setImage(currentImage);
        });

        observableList.add(firstKeyFrame);

        for (int i = 0; i < totalLayers; i++) {
            //create a keyframe for each layer
            KeyFrame keyFrame = new KeyFrame(Duration.millis(timeLocation = timeLocation + projectionTime), (ActionEvent t) -> {
                GizmoSlice gizmoSlice = queueImage.poll();
                System.out.println("display layer " + gizmoSlice.getLayer());
                Image currentImage = gizmoSlice.getFilledImage();
                sliceImageView.setImage(currentImage);
            });

            observableList.add(keyFrame);

        }

        engineTimeLine = TimelineBuilder.create()
                .cycleCount(1)
                .keyFrames(list)
                .autoReverse(false).build();
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
        totalLayers = 480;
        projectionTime = 400;
    }    

    class LayerProducer implements Runnable {

        private final PriorityQueue<GizmoSlice> queueImage;
        private boolean stop = false;
        private final int layer;
        private final String gizmoName;

        public void stopProducing() {
            stop = true;
        }

        public boolean isStopped() {
            return stop;
        }

        public LayerProducer(PriorityQueue<GizmoSlice> queueImage, int layer, String gizmoName) {
            this.queueImage = queueImage;
            this.layer = layer;
            this.gizmoName = gizmoName;
        }

        @Override
        public void run() {
            String imageFilename = gizmoName + "fill" + layer + "." + GIZMO_SLICE + ".png";
            File imageFile = new File(TEMP_DIRECTORY + imageFilename);
            Image img = new Image(imageFile.toURI().toString());
            ImageView imageView = new ImageView(img);
            imageView.setVisible(false);

            GizmoSlice gizmoSlice = new GizmoSlice();
            gizmoSlice.setName(imageFilename);
            gizmoSlice.setFilledImage(img);
            gizmoSlice.setFilledImageView(imageView);
            gizmoSlice.setLayer(layer);
            queueImage.add(gizmoSlice);
        }
    }

    public class GizmoSliceComparator implements Comparator<GizmoSlice> {

        @Override
        public int compare(GizmoSlice x, GizmoSlice y) {
            Long layerX = x.getLayer();
            Long layerY = y.getLayer();

            return layerX.compareTo(layerY);
        }
    }

}

我仍然在研究这个问题。

我更改了代码以创建一个队列来读取图像的字节,然后是第二个较小的队列,其中包含转换为图像的字节,但处理过多,内存太多。

我想我也弄清楚我之前的问题是CPU峰值。我给VM 10GB的内存,垃圾收集造成了问题。

我也尝试过堆外内存,但所有工具都需要序列化对象。我试图序列化,但它太慢了。

我现在正在使用ffmpeg(Generate video with ffmpeg to play using JavaFX)从图像文件生成一部电影,但我无法弄清楚如何让ffmpeg生成JavaFX可以显示的电影。昨晚我尝试使用代码在JavaFX中使用VLC查看器并显示所有生成的视频。只是不喜欢使用特定于操作系统的代码。此外,它使用50%CPU和8核i7,因此它可能无法在Raspberry PI上运行。我需要做更多的测试,看看我是否可以将电影的图像与ImageView对象的图像对齐

0 个答案:

没有答案