2015-01-11 3 views
1

JavaFX에서 '정리'해야 할 창이 있습니다. 모든 필드의 값을 재설정하고 초기화 된 시점으로 다시 설정하십시오. 내가 window.dispose()과 같은 것을 할 수 있다고 생각했지만, 존재하는 것처럼 보이지는 않습니다.JavaFX - 창 처분

계속 유지하고 싶지 않은 여러 창을 여는 것처럼 이것은 창 엔진의 방대한 감독처럼 보입니다. 만약 내가 stage.close()하면 그냥 메모리 누출로 이어질 메모리를 공개하지 않고 창을 숨 깁니다.

+1

'stage.close()'가 메모리 누수를 초래한다는 결론에 어떻게 도달 했습니까? 역 참조하는 객체에 다른 강력한 참조가있는 경우에만 (다른 Java 객체와 마찬가지로) 이러한 상황이 발생합니다. – eckig

+0

글쎄, 나는'.close()'및 부활 한 창을 가지고 있고, 그것들에 적용된 데이터를 유지한다. 그래서 나는 새롭고'.close()'를 만들고, 결국 나는 실행하지 않을 것이라고 생각한다. memory – JamEngulfer

+0

실제로 close()는 hide()를 호출하는 것과 같습니다. 스테이지를 파괴하지 않으므로 모든 정보가 내부에 저장됩니다. [doc here] (https://docs.oracle.com/javafx/2/api/javafx/stage/Stage.html#close())를 참조하십시오 (JavaFX 8의 경우 동일한 이야기). JavaFX를 사용하면 응용 프로그램의 라이프 사이클이 끝날 때만 자원이 릴리스됩니다 ([doc here 참조] (http://docs.oracle.com/javafx/2/api/javafx/application/Application.html)). 내 응용 프로그램 중 하나에서 수행 한 작업은 내 필드를 속성으로 바인딩하는 것입니다. 이 방법으로 모든 값을 속성에서 직접 제어 할 수 있습니다 (양방향 바인딩). – VinceOPS

답변

2

close() (또는 이와 동등한 방법으로 hide())을 창에 호출하면 FX 도구 키트는 해당 창에 대해 보유한 참조를 모두 해제합니다. 결과적으로 윈도우에 대한 참조를 유지하지 않는 한 close()이 호출되면 가비지 콜렉션을 사용할 수있게됩니다. 가비지 콜렉션과 관련하여 다른 Java 객체처럼 동작합니다. 일단 가비지 수집이 수행되면 윈도우와 관련된 리소스가 해제됩니다.

다음은 새로운 창을 매초 열어 이전 창을 닫을 때 데모입니다. 창은 레이블에 이미지를 표시하므로 합리적인 메모리 덩어리를 소비합니다. 기본 단계는 메모리 통계를 표시합니다 (매 초마다 업데이트). 가비지 컬렉터가 시작될 때까지 메모리가 점차 증가하면서 예상대로 작동합니다. 메모리 사용량이 다시 줄어 듭니다. (내 시스템에서는 ~ 7MB와 ~ 65MB 사이에서 순환하며, OS, JDK 버전 및 시스템 자원에 따라 마일리지가 다를 수 있습니다.) onSucceeded 처리기 끝에 System.gc();에 대한 호출을 삽입 할 수 있습니다 (데모 용으로 만; 가비지 컬렉션이 모든 리소스를 해제한다는 것을보다 명확하게보고 싶다면 실제 코드에서이 작업을 수행하지 않는 것이 좋습니다.

import java.util.Random; 
import java.util.concurrent.atomic.AtomicInteger; 

import javafx.animation.Animation; 
import javafx.animation.KeyFrame; 
import javafx.animation.Timeline; 
import javafx.application.Application; 
import javafx.beans.binding.NumberBinding; 
import javafx.beans.property.LongProperty; 
import javafx.beans.property.ObjectProperty; 
import javafx.beans.property.SimpleLongProperty; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.concurrent.ScheduledService; 
import javafx.concurrent.Task; 
import javafx.geometry.Pos; 
import javafx.scene.Scene; 
import javafx.scene.chart.LineChart; 
import javafx.scene.chart.NumberAxis; 
import javafx.scene.chart.XYChart.Data; 
import javafx.scene.chart.XYChart.Series; 
import javafx.scene.control.ContentDisplay; 
import javafx.scene.control.Label; 
import javafx.scene.image.ImageView; 
import javafx.scene.image.PixelWriter; 
import javafx.scene.image.WritableImage; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.Pane; 
import javafx.scene.layout.StackPane; 
import javafx.scene.layout.VBox; 
import javafx.scene.paint.Color; 
import javafx.stage.Screen; 
import javafx.stage.Stage; 
import javafx.util.Duration; 

public class ConstantlyOpenWindows extends Application { 

    @Override 
    public void start(Stage primaryStage) { 

     ScheduledService<?> service = periodicallyShowNewWindow(); 

     Pane root = createMemoryMonitor(); 
     primaryStage.setScene(new Scene(root, 800, 600)); 

     primaryStage.show(); 

     service.start(); 

    } 


    private ScheduledService<Integer> periodicallyShowNewWindow() { 

     Screen screen = Screen.getPrimary(); 
     double maxX = screen.getBounds().getMaxX(); 

     AtomicInteger count = new AtomicInteger(); 
     ObjectProperty<Stage> visibleStage = new SimpleObjectProperty<>(); 
     ScheduledService<Integer> service = new ScheduledService<Integer>() { 
      @Override 
      protected Task<Integer> createTask() { 
       Task<Integer> task = new Task<Integer>() { 
        @Override 
        public Integer call() { 
         return count.incrementAndGet(); 
        } 
       }; 
       return task ; 
      } 
     }; 

     service.setOnSucceeded(event -> { 
      Stage lastStage = visibleStage.get(); 
      Stage stage = createWindowWithImage(service.getValue()); 
      visibleStage.set(stage); 
      stage.setX(maxX - 480); 
      stage.show(); 
      if (lastStage != null) { 
       lastStage.close(); 
      } 
//   System.gc(); 
     }); 

     service.setPeriod(Duration.seconds(1)); 
     return service; 
    } 


    private Stage createWindowWithImage(int count) { 
     Stage stage = new Stage(); 
     ImageView image = createImage(); 
     Label label = new Label("Window "+count); 
     label.setGraphic(image); 
     label.setContentDisplay(ContentDisplay.BOTTOM); 
     stage.setScene(new Scene(new StackPane(label), 480, 500)); 
     return stage; 
    } 

    private ImageView createImage() { 
     WritableImage img = new WritableImage(400, 400); 
     Random rng = new Random(); 
     int x = rng.nextInt(40); 
     int y = rng.nextInt(40); 
     PixelWriter pw = img.getPixelWriter(); 
     for (int i = 0; i < 400; i++) { 
      for (int j = 0 ; j < 400 ; j++) { 
       if (i >= x*10 && i < (x+1)*10 && j >= y*10 && j < (y+1) * 10) { 
        pw.setColor(i, j, Color.CORNFLOWERBLUE); 
       } else { 
        pw.setColor(i, j, Color.ANTIQUEWHITE); 
       } 
      } 
     } 
     return new ImageView(img); 
    } 

    private Pane createMemoryMonitor() { 
     LongProperty totalMemory = new SimpleLongProperty(Runtime.getRuntime().totalMemory()); 
     LongProperty freeMemory = new SimpleLongProperty(Runtime.getRuntime().freeMemory()); 
     LongProperty maxMemory = new SimpleLongProperty(Runtime.getRuntime().maxMemory()); 
     NumberBinding usedMemory = totalMemory.subtract(freeMemory); 

     Label usedMemoryLabel = new Label(); 
     usedMemoryLabel.textProperty().bind(usedMemory.asString("Used memory: %,d")); 
     Label freeMemoryLabel = new Label(); 
     freeMemoryLabel.textProperty().bind(freeMemory.asString("Free memory: %,d")); 
     Label totalMemoryLabel = new Label(); 
     totalMemoryLabel.textProperty().bind(totalMemory.asString("Total memory: %,d")); 
     Label maxMemoryLabel = new Label(); 
     maxMemoryLabel.textProperty().bind(maxMemory.asString("Max memory: %,d")); 

     Series<Number, Number> series = new Series<>(); 
     series.setName("Used memory"); 

     AtomicInteger time = new AtomicInteger(); 

     Timeline updateMemory = new Timeline(new KeyFrame(Duration.seconds(1), event -> { 
      totalMemory.set(Runtime.getRuntime().totalMemory()); 
      freeMemory.set(Runtime.getRuntime().freeMemory()); 
      maxMemory.set(Runtime.getRuntime().maxMemory()); 
      series.getData().add(new Data<>(time.incrementAndGet(), usedMemory.getValue())); 
      if (series.getData().size() > 100) { 
       series.getData().subList(0, series.getData().size() - 100).clear(); 
      }  
     })); 
     updateMemory.setCycleCount(Animation.INDEFINITE); 
     updateMemory.play(); 

     VBox labels = new VBox(usedMemoryLabel, freeMemoryLabel, totalMemoryLabel, maxMemoryLabel); 
     labels.setAlignment(Pos.CENTER); 

     NumberAxis xAxis = new NumberAxis(); 
     xAxis.setLabel("Time"); 
     xAxis.setForceZeroInRange(false); 
     NumberAxis yAxis = new NumberAxis(); 
     yAxis.setLabel("Memory"); 
     LineChart<Number, Number> chart = new LineChart<Number, Number>(xAxis, yAxis); 
     chart.setAnimated(false); 
     chart.getData().add(series); 

     BorderPane root = new BorderPane(chart, labels, null, null, null); 

     return root; 
    } 

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

'javafx.concurrent.ScheduledService'가 실제로 제 설치물에 존재한다면, 당신의 데모를 실행할 것입니다. – JamEngulfer

+0

JDK7/JavaFX2를 여전히 사용하고 있다면 단지'Task' 만 생성하고'Platform .runLater (...)','Thread.sleep (...) '을 포함하고 있습니다. 또는 "메모리 모니터"에서와 같이 '타임 라인'을 사용하십시오.물론 모든 람다 식을 내부 클래스로 변경해야합니다. 이전 버전을 사용해야하는 이유가 있습니까? –

+0

필자는 Mac을 사용하기 때문에 Java 8을 사용할 수 없거나 중요한 것을 실행하지 못했기 때문에 설치하지 않았습니다. – JamEngulfer