我在KDE上使用64位Linux机器(8GB内存),Eclipse作为我的IDE。我也在使用Oracle的JDK。我使用JavaFX制作了一个小动画,并在网上制作了一些图片,以围绕太阳旋转地球。每当我运行它,动画正常工作,但它会稳定地吃掉我电脑上的所有RAM,直到一切都冻结。这通常不到5分钟。
package Practice;
/**
* For some reason, this code gobbles up memory, and freezes computers
*/
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class BasicAnimation extends Application {
public BasicAnimation() {
// TODO Auto-generated constructor stub
}
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Orbit");
Group root = new Group();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
Canvas canvas = new Canvas(512,512);
root.getChildren().add(canvas);
GraphicsContext gc = canvas.getGraphicsContext2D();
Image earth = new Image(getClass().getResourceAsStream("earth.png"), 25.0, 25.0 ,false, false);
Image sun = new Image(getClass().getResourceAsStream("sun.jpg"), 50.0, 50.0, false, false);
Image space = new Image(getClass().getResourceAsStream("space.jpg"));
final long startNanoTime = System.nanoTime();
new AnimationTimer() {
public void handle(long currentNanoTime) {
double t = (currentNanoTime - startNanoTime) / 1000000000.0 ;
double x = 232 + 128 * Math.cos(t);
double y = 232 + 128 * Math.sin(t);
//background image clears canvas
gc.drawImage(space, 0, 0);
gc.drawImage(earth, x, y);
gc.drawImage(sun, 196, 196);
}
}.start();
primaryStage.show();
}
}
我设置了-Xms512m,-Xmx512m和-Xss512m。有没有什么我做错了可能导致这种情况,你能解释为什么会发生这种情况或者如何避免它?
如果我的问题有问题,请告诉我。
编辑:添加了更多信息
地球图像为2356x2356,我在程序中将其设置为25x25px。太阳图像是750x750,我在程序中将其设置为50x50。空间图像为1920x1080,背景为512x512像素。
图像链接
太阳报:https://www.thesun.co.uk/wp-content/uploads/2016/06/download.jpg?w=750&strip=all
地球:https://openclipart.org/image/2400px/svg_to_png/218125/3d-Earth-Globe.png
空间:http://www.gunnars.com/wp-content/uploads/2014/08/Space.jpg
答案 0 :(得分:1)
gc.drawImage(space, 0, 0);
导致问题。恕我直言,你不应该为每一帧都打电话。
通常我们通过渲染帧来做动画。我们得到一个Graphics
对象,对于每个帧,我们清除画布并重绘所有内容。 但这并不是JavaFX中的工作方式。
在JavaFX中,通过在节点(形状,图像或组)上应用变换来实现动画。你设置场景,添加你的"演员",形状,图像等。然后你创建Animation
个对象来控制那些"演员"。
我不是专家,所以下面的例子只是展示了如何让圆圈围绕另一个旋转的想法。动议不统一。所以你肯定想要尝试不同的路径/过渡/动画。
更新:使用Path.setInterpolator(Interpolator.LINEAR)
删除加速
import javafx.animation.PathTransition;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.effect.BoxBlur;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
import javafx.util.Duration;
import static javafx.animation.Animation.INDEFINITE;
public class Animation extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("orbit");
Group root = new Group();
Scene scene = new Scene(root, 800, 800, Color.BLACK);
primaryStage.setScene(scene);
Circle sun = new Circle(50, Color.web("yellow", 1.0));
sun.setCenterX(400);
sun.setCenterY(400);
sun.setEffect(new BoxBlur(10, 10, 3));
Circle earth = new Circle(10, Color.web("blue"));
earth.setEffect(new BoxBlur(4, 4, 3));
root.getChildren().add(sun);
root.getChildren().add(earth);
Path path = new Path();
ArcTo arcTo = new ArcTo();
arcTo.setX(20);
arcTo.setY(401);
arcTo.setSweepFlag(true);
arcTo.setLargeArcFlag(true);
arcTo.setRadiusX(400);
arcTo.setRadiusY(400);
arcTo.setXAxisRotation(0);
path.getElements().add(new MoveTo(20, 400));
path.getElements().add(arcTo);
path.getElements().add(new ClosePath());
path.setVisible(false);
PathTransition pt = new PathTransition(Duration.seconds(10), path, earth);
pt.setInterpolator(Interpolator.LINEAR); // No acceleration/deceleration
pt.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT);
pt.setCycleCount(INDEFINITE);
pt.play();
primaryStage.show();
}
}
答案 1 :(得分:1)
我的代码中看不到任何错误。它可能不是在JavaFX中执行此操作的最佳方式,但它对我来说看起来非常有效,不应该占用任何内存。特别是当你说你和Luke的其他代码有同样的问题我怀疑有一些Linux bug。您是否尝试在其他操作系统上运行程序?如果您提供图片链接,其他人也可以尝试。
此链接可能与您的问题有关: javafx-unexplainable-leaks-memory-on-linux
<强>测试强>
我在Mac上运行你的程序,没有内存泄漏,几乎没有CPU使用,正如我所期望的那样。
答案 2 :(得分:0)
tl; dr 使用JVM的-D.prism=sw
参数来解决问题。
JavaFX试图利用硬件加速,似乎新的Mesa和Xorg驱动程序并没有完全解决问题。我还认为VDPAU驱动程序(硬件加速驱动程序)有问题。当我使用JVM的-D.prism=sw
参数运行程序时,它将编译器设置为使用软件流水线而不是硬件加速,这个问题大大减少了。我仍然看到程序稳定地消耗内存,但过程要慢得多。
我还发现减少调用gc.drawimage()的次数也会增加填充RAM所需的时间。
new AnimationTimer() { //This is how I reduced the number of times gc.drawImage is called
long lastupdate = 0 ;
public void handle(long currentNanoTime) {
double t = (currentNanoTime - startNanoTime) / 1000000000.0 ;
double x = 232 + 128 * Math.cos(t);
double y = 232 + 128 * Math.sin(t);
//background image clears canvas
if(currentNanoTime - lastupdate >= 33333333) {
gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
gc.drawImage(space, 0, 0);
gc.drawImage(sun, 196, 196);
gc.drawImage(earth, x, y);
lastupdate = currentNanoTime;
}
}
}.start();
那里可能存在垃圾收集问题,但我不确定。我将稍后使用VisualVM进行检查,然后我会更新此答案。
<强>更新强> 垃圾收集没有问题。内存现在稳定,并通过启用软件流水线来稳定。 JavaFX似乎与VDPAU不兼容。谢谢你的帮助!
来源: