Problem with Timeline keeping references around
John Hendrikx
hjohn at xs4all.nl
Tue Oct 15 17:48:20 PDT 2013
I'm having trouble creating a reproducable test case.
There seems to be more going on -- if I open and close the Pane involved
several times, eventually some of them will start to be GC'd (but never
all, unless I disable the animation). I've used VisualVM to inspect the
Pane involved, and here is what it says is keeping it alive (clearly
something animation related atleast):
this - value: hs.mediasystem.screens.playback.PlaybackOverlayPane #1
<- this$0 - class: javafx.scene.Node$8, value:
hs.mediasystem.screens.playback.PlaybackOverlayPane #1
<- target - class:
com.sun.scenario.animation.shared.InterpolationInterval$DoubleInterpolationInterval,
value: javafx.scene.Node$8 #149
<- [0] - class:
com.sun.scenario.animation.shared.InterpolationInterval[], value:
com.sun.scenario.animation.shared.InterpolationInterval$DoubleInterpolationInterval
#28
<- [0] - class:
com.sun.scenario.animation.shared.InterpolationInterval[][], value:
com.sun.scenario.animation.shared.InterpolationInterval[] #10 (3 items)
<- interval - class:
com.sun.scenario.animation.shared.GeneralClipInterpolator, value:
com.sun.scenario.animation.shared.InterpolationInterval[][] #16 (1 items)
<- clipInterpolator - class:
com.sun.scenario.animation.shared.TimelineClipCore, value:
com.sun.scenario.animation.shared.GeneralClipInterpolator #16
<- clipCore - class: javafx.animation.Timeline, value:
com.sun.scenario.animation.shared.TimelineClipCore #19
<- this$0 - class: javafx.animation.Animation$1, value:
javafx.animation.Timeline #19
<- [5] - class: com.sun.scenario.animation.shared.PulseReceiver[],
value: javafx.animation.Animation$1 #19
<- receivers - class: com.sun.javafx.tk.quantum.MasterTimer, value:
com.sun.scenario.animation.shared.PulseReceiver[] #1 (7 items)
<- this$0 - class:
com.sun.scenario.animation.AbstractMasterTimer$MainLoop, value:
com.sun.javafx.tk.quantum.MasterTimer #1
<- animationRunnable - class:
com.sun.javafx.tk.quantum.QuantumToolkit, value:
com.sun.scenario.animation.AbstractMasterTimer$MainLoop #1
<- this$0 (JNI global) - class:
com.sun.javafx.tk.quantum.QuantumToolkit$14, value:
com.sun.javafx.tk.quantum.QuantumToolkit #1
If that is enough for a bugreport, I'll create one. A naive simple test
case which spawns several panes and animations was unable to reproduce
this issue I'm having:
package hs.mediasystem;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.beans.value.WeakChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class TimelineGCProblem extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage stage) throws Exception {
StackPane rootPane = new StackPane();
Scene scene = new Scene(rootPane);
stage.setScene(scene);
stage.show();
new Thread() {
@Override
public void run() {
for(;;) {
Platform.runLater(new Runnable() {
@Override
public void run() {
rootPane.getChildren().setAll(new FadeInPane());
}
});
try {
System.gc();
Thread.sleep(1500);
System.gc();
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
public static class FadeInPane extends StackPane {
private final Timeline fadeInSustainAndFadeOut = new Timeline(
new KeyFrame(Duration.seconds(0)),
new KeyFrame(Duration.seconds(1), new KeyValue(opacityProperty(),
1.0)),
new KeyFrame(Duration.seconds(6), new KeyValue(opacityProperty(),
1.0)),
new KeyFrame(Duration.seconds(8), new KeyValue(opacityProperty(),
0.0))
);
private final ChangeListener<Scene> sceneChangeListener = new
ChangeListener<Scene>() {
@Override
public void changed(ObservableValue<? extends Scene> observable,
Scene oldValue, Scene newValue) {
if(newValue != null) {
System.out.println(">>> Starting fadeIn anim");
fadeInSustainAndFadeOut.playFromStart();
}
else {
System.out.println(">>> Stopping fadeIn anim");
fadeInSustainAndFadeOut.stop();
}
}
};
public FadeInPane() {
sceneProperty().addListener(new
WeakChangeListener<>(sceneChangeListener));
setStyle("background-color: red");
getChildren().add(new Button("Hi"));
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("FadeInPane finalized");
}
}
}
--John
On 16/10/2013 00:47, Stephen F Northover wrote:
> This looks like a bug. Timeline should not be holding on to
> references. Please enter a JIRA.
>
> Steve
>
> On 2013-10-15 6:35 PM, John Hendrikx wrote:
>> Hi List,
>>
>> I just submitted https://javafx-jira.kenai.com/browse/RT-33600 which
>> is asking for the Timeline JavaDocs to be more clear on when and
>> where hard references are being created and how to properly clean up
>> after oneself. Most of the docs hardly mention anything when it
>> comes to references causing memory leaks, and Timeline is no exception.
>>
>> However, apart from the docs not really discussing this topic, I
>> actually cannot get proper cleanup to work at all when working with a
>> Timeline.
>>
>> If my Timeline is referencing properties from a StackPane and the
>> Timeline was run atleast once, I cannot figure out how to get this
>> Pane to be gc'd. Calling stop() and even doing
>> getKeyFrames().clear() doesn't help. I'm sure it must be the
>> Timeline because if I remove the KeyFrames that access the StackPane,
>> it will get gc'd properly. If I never run the animation, it also
>> gets gc'd properly.
>>
>> See code below. The System.outs will occur exactly as expected when
>> the StackPane becomes part of the Scene and when it is removed from
>> the Scene. I call stop() on my Timeline and even clear its
>> KeyFrames, but the StackPane refuses to be gc'd (even after hitting
>> the GC button I created for this occasion dozens of times).
>>
>> Not calling playFromStart() or not using the KeyFrames that refer to
>> detailsOverlay.opacityProperty() will solve the problem, and the
>> finalize() System.out will occur usually after the first or second
>> time I press my GC button.
>>
>> Anything else I can try or is this a bug?
>> --John
>>
>> public class PlaybackOverlayPane extends StackPane {
>> private final Timeline fadeInSustainAndFadeOut = new Timeline(
>> new KeyFrame(Duration.seconds(0)),
>> new KeyFrame(Duration.seconds(1), new
>> KeyValue(detailsOverlay.opacityProperty(), 1.0)),
>> new KeyFrame(Duration.seconds(6), new
>> KeyValue(detailsOverlay.opacityProperty(), 1.0)),
>> new KeyFrame(Duration.seconds(9), new
>> KeyValue(detailsOverlay.opacityProperty(), 0.0))
>> );
>>
>> private final ChangeListener<Scene> sceneChangeListener = new
>> ChangeListener<Scene>() {
>> @Override
>> public void changed(ObservableValue<? extends Scene> observable,
>> Scene oldValue, Scene newValue) {
>> if(newValue != null) {
>> System.out.println(">>> Starting fadeIn anim");
>> fadeInSustainAndFadeOut.playFromStart();
>> }
>> else {
>> System.out.println(">>> Stopping fadeIn anim");
>> fadeInSustainAndFadeOut.stop();
>> fadeInSustainAndFadeOut.getKeyFrames().clear();
>> fadeInSustainAndFadeOut.stop();
>> }
>> }
>> };
>>
>> private final GridPane detailsOverlay = GridPaneUtil.create(new
>> double[] {5, 20, 5, 65, 5}, new double[] {45, 50, 5});
>>
>> ...
>>
>> @Override
>> protected void finalize() throws Throwable {
>> super.finalize();
>> System.out.println(">>> Finalized " + this);
>> }
>> }
>
More information about the openjfx-dev
mailing list