2016-12-01 72 views
4

我在KDE上使用64位Linux機器(8GB RAM)作爲我的IDE。我也在使用Oracle的JDK。我用JavaFX製作了一個小動畫,還有一些網頁上的照片讓地球繞着太陽轉動。每當我運行它時,動畫都能正常工作,但它會穩定地吃掉我電腦上的所有RAM,直到一切凍結。這通常不到5分鐘。JVM消耗40行代碼中的所有RAM

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

+1

我猜的一個很好的例子'gc.drawImage'是罪魁禍首 –

+0

什麼是你的圖像的尺寸? – TameHog

+0

請參閱[Java FX動畫示例](http://docs.oracle.com/javafx/2/get_started/animation.htm) –

回答

1

我看不出什麼錯在你的代碼。這可能不是在JavaFX中完成此操作的最佳方式,但它對我來說看起來完全合法,不應該吃掉任何內存。特別是當你說你和Luke的其他代碼有同樣的問題時,我懷疑有一些Linux的bug。你有沒有試過在另一個操作系統上運行你的程如果你提供了鏈接到你的圖片,別人也可以嘗試。

此鏈接可能與您的問題: javafx-unexplainable-leaks-memory-on-linux

測試

我Mac上運行了你的程序,也沒有內存泄漏,幾乎沒有CPU使用率,正如我預料的要。

+0

我曾經幫助解決了一個在Linux上也是瘋狂的記憶。問題出在硬件加速的問題上,你可以使用'-Dprism.order = sw' JVM參數來使用軟件渲染。 – RAnders00

1

gc.drawImage(space, 0, 0);引起的問題。恕我直言,你不應該爲每一幀調用它。

通常我們通過渲染幀來進行動畫。我們得到一個Graphics對象,並且對於每一幀我們都清除畫布並重繪所有內容。 但這並不是JavaFX中的工作方式。

在JavaFX中,動畫是通過對節點(形狀,圖像或組)應用轉換來實現的。您設置場景,添加您的「演員」,形狀,圖像等。然後創建控制這些「演員」的對象。

我不是專家,所以下面的例子只是演示瞭如何使一個圓形圍繞另一個旋轉的想法。議案不統一。所以你一定要嘗試不同的路徑/轉換/動畫。

更新:使用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(); 
    } 
} 
+0

我試過這個,我得到同樣的問題。不過謝謝你的建議! – Jal

0

tl; dr使用-D.prism=sw參數爲JVM解決問題。

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。感謝所有的幫助!

來源:

https://github.com/jfoenixadmin/JFoenix/issues/52

https://bugs.openjdk.java.net/browse/JDK-8161997

0

你的榜樣工作正常的Windows 7與Java 8 64位和內存是穩定的。

檢查VisualVM的截圖:enter image description here

但是你不斷繪製在屏幕上,我認爲在你的系統中新的圖形都沒有收集足夠快的垃圾。

如果您評論空間圖:gc.drawImage(space,0,0); 你可以看到真正是怎麼回事

enter image description here

你的計劃「作品」,但其真正低效

你也並不需要512MB(-Xss512m)的堆棧大小!

退房在JavaFX here動畫例子