Yesterday was a bad day because one of the node after updating to tomcat7 ran into full garbage collection. I took a heap dump and finally found that one of the enhanced class had 300K references hanging around in finalizer thread. I was enhancing SimpelJDBCTemplate to find out time taken by each query and log it. The reason this happened because CGLib also enhanced the finalize method and in the method interceptor I was delegating the call to the delegate object which was not existing at that time. Anyways the solution was to skip the enhancing of finalize by adding a callback filter and nooping on it.
As you can see in below code the filter returns 0 if finalize method is called and that means use the callback at 0th position in the callbacks which is a NoOp callback and for all others it uses 1st position which is my real code.
The simple code fix was
public static SimpleJdbcTemplate createPerfInterceptedTemplate(Class callerClass, DataSource dataSource) {
final SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
final String className = callerClass.getSimpleName();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SimpleJdbcTemplate.class);
enhancer.setCallbackFilter(FINALIZE_FILTER);
enhancer.setCallbacks(new Callback[]{NoOp.INSTANCE, new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
..........do your real delegate code here..........
}
}
}
private static final CallbackFilter FINALIZE_FILTER = new CallbackFilter() {
public int accept(Method method) {
if (method.getName().equals("finalize") &&
method.getParameterTypes().length == 0 &&
method.getReturnType() == Void.TYPE) {
return 0;
}
return 1;
}
};
As you can see in below code the filter returns 0 if finalize method is called and that means use the callback at 0th position in the callbacks which is a NoOp callback and for all others it uses 1st position which is my real code.
The simple code fix was
public static SimpleJdbcTemplate createPerfInterceptedTemplate(Class callerClass, DataSource dataSource) {
final SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
final String className = callerClass.getSimpleName();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SimpleJdbcTemplate.class);
enhancer.setCallbackFilter(FINALIZE_FILTER);
enhancer.setCallbacks(new Callback[]{NoOp.INSTANCE, new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
..........do your real delegate code here..........
}
}
}
private static final CallbackFilter FINALIZE_FILTER = new CallbackFilter() {
public int accept(Method method) {
if (method.getName().equals("finalize") &&
method.getParameterTypes().length == 0 &&
method.getReturnType() == Void.TYPE) {
return 0;
}
return 1;
}
};
Comments
Post a Comment