JavaBeanObjectPropertys are not gargabe collected, continuously producing them results in a OutOfMemoryException.
This minimal setup produces the exception:
===============
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import javafx.beans.property.adapter.JavaBeanObjectProperty;
import javafx.beans.property.adapter.JavaBeanObjectPropertyBuilder;
import org.junit.Test;
public class MemoryLeakTest {
public class FaceBean {
private int mouthWidth = 90;
private final PropertyChangeSupport mPcs = new PropertyChangeSupport(this);
public int getMouthWidth() {
return mouthWidth;
}
public void setMouthWidth(final int mw) {
int oldMouthWidth = mouthWidth;
mouthWidth = mw;
mPcs.firePropertyChange("mouthWidth", oldMouthWidth, mw);
}
public void addPropertyChangeListener(final PropertyChangeListener listener) {
mPcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(final PropertyChangeListener listener) {
mPcs.removePropertyChangeListener(listener);
}
}
@Test
@SuppressWarnings({ "unchecked" })
public void produceMemoryLeak() throws NoSuchMethodException {
while (true) {
FaceBean faceBean = new FaceBean();
JavaBeanObjectPropertyBuilder<?> builder = new JavaBeanObjectPropertyBuilder<>();
JavaBeanObjectProperty<Integer> mouthWidthProperty = builder.bean(faceBean).name("mouthWidth").build();
mouthWidthProperty.dispose();
mouthWidthProperty.unbind();
}
}
}
===============
The problem is in the JavaBeanObjectProperty's constructor. Removing the following part resolves the OutOfMemoryException.
===============
Cleaner.create(this, new Runnable() {
@Override
public void run() {
JavaBeanObjectProperty.this.descriptor.removeListener(listener);
}
});
===============
Inspecting the heap shows that the cleaner never gets collected, holding a reference to the JavaBeanObjectProperty, which ultimately holds a reference to the value object, so it won't be collected either.
This minimal setup produces the exception:
===============
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import javafx.beans.property.adapter.JavaBeanObjectProperty;
import javafx.beans.property.adapter.JavaBeanObjectPropertyBuilder;
import org.junit.Test;
public class MemoryLeakTest {
public class FaceBean {
private int mouthWidth = 90;
private final PropertyChangeSupport mPcs = new PropertyChangeSupport(this);
public int getMouthWidth() {
return mouthWidth;
}
public void setMouthWidth(final int mw) {
int oldMouthWidth = mouthWidth;
mouthWidth = mw;
mPcs.firePropertyChange("mouthWidth", oldMouthWidth, mw);
}
public void addPropertyChangeListener(final PropertyChangeListener listener) {
mPcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(final PropertyChangeListener listener) {
mPcs.removePropertyChangeListener(listener);
}
}
@Test
@SuppressWarnings({ "unchecked" })
public void produceMemoryLeak() throws NoSuchMethodException {
while (true) {
FaceBean faceBean = new FaceBean();
JavaBeanObjectPropertyBuilder<?> builder = new JavaBeanObjectPropertyBuilder<>();
JavaBeanObjectProperty<Integer> mouthWidthProperty = builder.bean(faceBean).name("mouthWidth").build();
mouthWidthProperty.dispose();
mouthWidthProperty.unbind();
}
}
}
===============
The problem is in the JavaBeanObjectProperty's constructor. Removing the following part resolves the OutOfMemoryException.
===============
Cleaner.create(this, new Runnable() {
@Override
public void run() {
JavaBeanObjectProperty.this.descriptor.removeListener(listener);
}
});
===============
Inspecting the heap shows that the cleaner never gets collected, holding a reference to the JavaBeanObjectProperty, which ultimately holds a reference to the value object, so it won't be collected either.
- duplicates
-
JDK-8096087 JavaBeanProperty: memory leak?
-
- Resolved
-