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);
}
}
'stage.close()'가 메모리 누수를 초래한다는 결론에 어떻게 도달 했습니까? 역 참조하는 객체에 다른 강력한 참조가있는 경우에만 (다른 Java 객체와 마찬가지로) 이러한 상황이 발생합니다. – eckig
글쎄, 나는'.close()'및 부활 한 창을 가지고 있고, 그것들에 적용된 데이터를 유지한다. 그래서 나는 새롭고'.close()'를 만들고, 결국 나는 실행하지 않을 것이라고 생각한다. memory – JamEngulfer
실제로 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