原因
The listener like changeListener, invalidationListener, EventHandler hold the strong reference of UI. And then somehow finally will be holded by
a fx static root object.
一些监听器诸如changeListener, invalidationListener , EventHandler 持有了UI 的强引用, 而这些监听起又被某些fx property 所持有, 而fx的某些property又被某些静态根对象所持有。
最后导致UI对象一直被持有而无法释放,从而导致了内存泄漏。
样例 normal case
ToolTip泄漏
引用链:component-> MouseListener ->持有 chartTooltipBehavior实例 -> 持有FXToolTipHandler实例-> 持有ToolTIp->… -> 最终持有 AutoSelectioHeatMapPlotPoint (一个HeatMap block对象)
该component是JLightFrame的一个实例, 此处代码应该是chartDirector 基于swing的实现, 最终被disposer的records的根对象处理。
这里我们两种方案解决这个内存泄漏,
fix Disposer的源码, value对象使用weakReference存储
fix mouseLisenter,使上层 Ui 对象得到回收
PatternConstrainCodeArea泄漏
引用链:lamda 对象-> 持有content->持有richChangeList-> …. -> PatternConstrainCodeArea对象
避免内存泄漏的建议
- 禁止使用匿名内部类表达式 (匿名内部类对象一定持有当前上下文this对象)
- 使用lamda表达式或者静态内部类
- 在lamda表达式以及静态内部类中 对于外部对象, 使用弱引用(尤其是UI)。
使用weakReference 封装需要在lambda表达式1
2
3
4
5
6
7
8
9
10
11
12
13
14public static <O> InvalidationListener weak(O obj, Action2<Observable, O> listener) {
WeakReference<O> weak = new WeakReference<>(obj);
return new InvalidationListener() {
public void invalidated(Observable ob) {
O object = weak.get();
if (object == null) { // isDispose() == true
ob.removeListener(this);
} else { // 类似在swt 中 判断 isDispose() == false
listener.call(ob, object);
}
}
};
}