Leisure Moment

乱花渐欲迷人眼,浅草才能没马蹄。最爱湖东行不足,绿杨阴里白沙堤。


  • Home

  • Archives

  • Tags

  • About

  • Sitemap

fx中的内存泄漏问题

Posted on 2019-04-10 | In java_fx

原因

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泄漏

leak_1
引用链:component-> MouseListener ->持有 chartTooltipBehavior实例 -> 持有FXToolTipHandler实例-> 持有ToolTIp->… -> 最终持有 AutoSelectioHeatMapPlotPoint (一个HeatMap block对象)
该component是JLightFrame的一个实例, 此处代码应该是chartDirector 基于swing的实现, 最终被disposer的records的根对象处理。

这里我们两种方案解决这个内存泄漏,
fix Disposer的源码, value对象使用weakReference存储
fix mouseLisenter,使上层 Ui 对象得到回收

PatternConstrainCodeArea泄漏

leak2
引用链:lamda 对象-> 持有content->持有richChangeList-> …. -> PatternConstrainCodeArea对象

避免内存泄漏的建议

  1. 禁止使用匿名内部类表达式 (匿名内部类对象一定持有当前上下文this对象)
  2. 使用lamda表达式或者静态内部类
  3. 在lamda表达式以及静态内部类中 对于外部对象, 使用弱引用(尤其是UI)。
    使用weakReference 封装需要在lambda表达式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public static <O> InvalidationListener weak(O obj, Action2<Observable, O> listener) {
    WeakReference<O> weak = new WeakReference<>(obj);
    return new InvalidationListener() {
    @Override
    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);
    }
    }
    };
    }

AOP实践

Posted on 2019-04-05

AOP

面向切面编程实际上做一个代码增强, AOP像OOP一样是一种编程范式。 我们不光可以对方法进行增强,
也可以对构造函数,字段进行增强。(例如使用aspect J). 这里我只关注方法执行过程前后的织入,也就是运行期进行织入。

根据织入的时期,可以分为以下几个时期

  • 编译前
  • 编译后
  • 装载后
  • 运行期

比较有名的Spring AOP 是在运行期实现代码增强。
Spring AOP 基于以下两种实现,当代理对象实现某个接口时候会优先采用jdk动态代理, 如果代理对象无任何接口实现则基于CGlib 实现动态代理

动态代理

基于JDK的动态代理

  1. 定义一个回调类定义拦截后的方法回调对象(implement InvocationHandler)
  2. 使用Proxy.newProxyInstance() 生成代理对象。该方法有三个参数, 第一个是所属的classloader.
    第二个是该代理对象实现的接口的数组, 第三个是1定义的回调对象
1
2
3
4
5
6
7
8
9
10
class AppClientProxyHandler implements InvocationHandler {
public final AppClient bind(AppClientPool pool) {
this.pool = pool;
return (AppClient) (Proxy.newProxyInstance(
pool.getClass().getClassLoader(), new Class<?>[] {AppClient.class}, this));
}
@override
public final Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
}
}

AppClientProxyHandler 动态代理 AppClient 接口,对于applient 接口的调用都会被代理

增强的代码就是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
RpcConnection<D4cRpcClient, CommD4cService.Client> conn = pool.getAvailableConnnection();
try {
return call(method, conn.getInterfaces(), args);
} catch (Exception e) {
Throwable rootCause = e.getCause();
if (rootCause instanceof AppClientException || rootCause instanceof UtilException) {
throw rootCause;
} else {
LOGGER.error(e.getMessage(), e);
throw new ServerFail("Fatal error during call app service", e);
}
} finally {
pool.pushBack(conn);
}

增强目的:重复使用pool中“可贵“资源RpcConnection

基于CGLib方案

对于每个DAO调用之前做方法拦截回调, 检查版本是否符合预期,不符合预期不加载, 类似于权限检查。
事实上对于sesion 的权限检查也应该基于AOP去做。 对于版本更新,则在sava成功之后去做。

  1. 定义方法调用前回调对象
    在dao真正调用前进行”版本检测”
1
2
3
4
5
6
7
8
public class VersionCheckHandler implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
handleBefore(method, args);// version check
return proxy.invokeSuper(obj, args);
}

}
  1. 定义方法调用后回调对象
    在dao完成写操作后,进行“写版本”操作
1
2
3
4
5
6
7
8
public class VersionSaveHandler implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object object = proxy.invokeSuper(obj, args);
handleAfter(method, args);// version save
return object;
}
}
  1. 对于原来的DAO进行”代理”增强, 生成新的DAO 对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ProxyFactory {
public static <T> T getProxy(T targetObject, List<MethodInterceptor> handlers, CallbackFilter filter) {
if (!handlers.isEmpty()) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetObject.getClass());
List<Callback> callbacks = Lists.newArrayList();
for (int i = 0; i < handlers.size(); i++) {
callbacks.add(handlers.get(i));
}
enhancer.setCallbacks(callbacks.toArray(new Callback[callbacks.size()]));
if (filter != null) {
enhancer.setCallbackFilter(filter);
}
return (T) enhancer.create();
} else {
return targetObject;
}
}
}

AOP编程思想

OOP的有效补充(引用于知乎)

  • 面向对象(OOP)引入了继承、多态、封装,将系统的业务功能按照模块划分,每个模块用一个或多个类来表示。
  • 而对于一些系统功能,无法使用OOP的思想来实现它们。这些系统功能往往穿插在业务功能的各处,和业务代码耦合在一起;而且系统功能往往会被重复使用,这就导致了模块不利于复用,这就是使用OOP实现系统功能的弊端。
  • AOP即为面向切面编程,它把系统需求按照功能分门归类,把它们封装在一个个切面中,然后再指定这些系统功能往业务功能中织入的规则。最后由第三方机构根据你指定的织入规则,将系统功能整合到业务功能中。

nginx

Posted on 2018-08-09

安装

brew install nginx

命令集

  1. 启动 nginx

配置

nginx -t 找到配置文件的位置

1234…8
zhong-wei

zhong-wei

23 posts
3 categories
7 tags
RSS
© 2016 - 2019 zhong-wei