Performance of Spring CGLIB and JDK proxies
So I noticed a couple of questions popping up on the Spring forums asking about the cost of using AOP in Spring. This is really a question of how expensive CGLIB or JDK proxies are.
Since I had no real idea (there are lots of "not than expensive" comments around) I decided to write a little test.
Essentially I construct X instances of a class, X instances of a CGLIB proxy of that class (cglib sub classes the target class) and X instances of a JDK proxy, and then called the same method on each instance and measured the time. Hardly conclusive, but enough to give an idea.
I assumed the impact was minimal; when X is 10000:
Unproxied: 926654(ns) 9(ms) cglib: 23986289(ns) 239(ms) Proxy: 70206129(ns) 702(ms)
I expected some over head, but notwhere near that much….. I was also suprised that CGLIB was almost 3 times quicker than JDK proxies (JDK1.5.0_06 on WinXP SP2).
It is still a long way away from being the bottleneck in any system I am likely to write, but good to know :)
I expect AspectJ style weaving is probably a lot more efficient because (IIUI) it modified the byte code directly. Of course, there is an overhead of the modification, but that is a one off…. But I may be so completely wrong :)
Code:
public class MyClassImpl implements MyClass {
public void doSomething() {
}
}
public interface MyClass {
void doSomething();
}
import junit.framework.TestCase;
import org.springframework.aop.framework.ProxyFactoryBean;
public final class ProxyTest extends TestCase {
public void testPerformance() {
int numberToExecute = 10000;
MyClass[] classes = new MyClass[numberToExecute];
for (int i = 0; i< numberToExecute; i++) {
classes[i] = new MyClassImpl();
}
MyClass[] cglibProxyClasses = new MyClassImpl[numberToExecute];
for (int i = 0; i< numberToExecute; i++) {
ProxyFactoryBean factoryBean = new ProxyFactoryBean();
factoryBean.setProxyTargetClass(true);
factoryBean.setTarget(classes[i]);
cglibProxyClasses[i] = (MyClass) factoryBean.getObject();
}
MyClass[] proxyClasses = new MyClass[numberToExecute];
for (int i = 0; i< numberToExecute; i++) {
ProxyFactoryBean factoryBean = new ProxyFactoryBean();
factoryBean.setProxyTargetClass(false);
factoryBean.setInterfaces(new Class[] {MyClass.class });
factoryBean.setTarget(classes[i]);
proxyClasses[i] = (MyClass) factoryBean.getObject();
}
long unproxyExecution = executeClasses(numberToExecute, classes);
displayResults("Unproxied", unproxyExecution);
long cglibExecution = executeClasses(numberToExecute, cglibProxyClasses);
displayResults("cglib", cglibExecution);
long proxyExecution = executeClasses(numberToExecute, proxyClasses);
displayResults("Proxy", proxyExecution);
}
private void displayResults(String label, long unproxyExecution) {
System.out.println(label + ": " + unproxyExecution + "(ns) " + (unproxyExecution / 100000) + "(ms)");
}
private long executeClasses(int numberToExecute, MyClass[] classes) {
long start = System.nanoTime();
for (int i = 0; i< numberToExecute; i++) {
classes[i].doSomething();
}
long end = System.nanoTime();
long execution = end – start;
return execution;
}
}
Alexander Snaps
Interesting… While I’m not completely convinced in such microbenchmarks, I’m pretty sure that 1ms = 1,000,000 ns and not 100,000 ;)
Sort of reassuring, cause thought your figures were pretty low…
29 Nov 2007, 05:24
Add a comment
You are not allowed to comment on this entry as it has restricted commenting permissions.