如何创建与另一个节点A具有完全相同的图形表示的JavaFX节点B,而不会增加内存占用量?

时间:2016-01-09 01:51:46

标签: java graphics javafx

我的团队正在解析指定图形元素的文件,然后克隆该图形以显示许多其他空间位置。由于广泛使用克隆,一个文件达到OutOfMemoryError。我还没有在JavaFX中发现一种机制来复制视觉效果,使其在场景图中多次出现,而每个节点都没有相同的内存占用。这些是矢量图形,而不是图像,我们主要使用Path个节点。

请帮助找到一种内存有效的方法来复制屏幕上的矢量图形,其中每个克隆可能具有其他克隆不共享的任意变换,并防止可能放大克隆的潜在像素化。我已经设计了下面这个问题的简短例子,在我的电脑上,使用Xmx512m在第一次运行(热身后15次)大约60秒后失败了。提升Xmx是一个自然的建议,但不是问题的答案。

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Random;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.PathElement;
import javafx.stage.Stage;

/**
 * An example of running out of memory by duplicating a complicated vector graphic.
 */
public class ReplicateVectorGraphic extends Application {

    private Pane drawingBoard;

    @Override
    public void start(Stage primaryStage) {
        drawingBoard = new Pane();
        Button runUntilOOME = new Button("run until OOME");
        runUntilOOME.setOnAction( this::generateGraphics );
        BorderPane root = new BorderPane(drawingBoard, runUntilOOME, null, null, null);
        Scene scene = new Scene(root,400,600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * Creates new nodes based on the graphics in the simulated (pseudorandom)
     * file until we run out of memory.
     *
     * @param ae
     *            An ignored event that kicked off the operation.
     */
    private void generateGraphics(ActionEvent ae) {
        int n = 0;
        Instant begin = Instant.now();
        try {
            Group completeGraphic = new Group();
            // Hitting 32k clones would be success. (YMMV, but bear in mind
            // arbitrary end-user hardware. also check your Xmx.)
            for (;n <Short.MAX_VALUE; n++) {
                Path p = new Path();
                // load data from the simulated file
                populatePath(p);
                completeGraphic.getChildren().add( p );
            }
            drawingBoard.getChildren().add( completeGraphic );
            new Alert(AlertType.INFORMATION, "32k graphics displayed!").show();
        } catch (OutOfMemoryError oome) {
            final int nbr = n;
            Platform.runLater( () -> displayAlert(nbr, ChronoUnit.SECONDS.between( begin, Instant.now())) );
        }
    }

    private static void displayAlert(long nbr, long seconds) {
        String m = "Cloned graphic "+nbr+" times in "+ seconds +" seconds.";
        Alert a = new Alert(AlertType.ERROR, m);
        a.setTitle( "OOME Alert" );
        a.show();
    }

    private static void populatePath(Path p) {
        // in lieu of a real graphic to load, we'll generate a
        // pseudorandom sequence of points that will be the same each time
        Random r = new Random(42);
        ObservableList<PathElement> pathElements = p.getElements();
        pathElements.add( new MoveTo(r.nextDouble(), r.nextDouble()) );
        // 2048 elements is a reasonable amount of detail for a vector graphic.
        // reducing the detail of the graphic is not an option. we have to load what we're given.
        for (int i=0; i<2048; i++) {
            pathElements.add( new LineTo(r.nextDouble(), r.nextDouble()) );
        }
    }

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

此代码也是bitbucket snippet。我也欢迎提交bitbucket。

1 个答案:

答案 0 :(得分:0)

与可能只在场景图中出现一次的节点相比,您可以自由地重复使用路径的路径元素。因此,不需要复制,这可以为您节省一些空间。

我也不明白为什么你在代码中增加两次“n”。