我的团队正在解析指定图形元素的文件,然后克隆该图形以显示许多其他空间位置。由于广泛使用克隆,一个文件达到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。
答案 0 :(得分:0)
与可能只在场景图中出现一次的节点相比,您可以自由地重复使用路径的路径元素。因此,不需要复制,这可以为您节省一些空间。
我也不明白为什么你在代码中增加两次“n”。