下面是我们使用动态代理(替代)来测量方法调用时间的代码。
问题是这样的:
我们的代理吞下一个real类的对象RealObject,然后SympleDynamicProxy.consumer(Interface iface)依次调用方法real.doSomething(),然后real.somethingElse(String arg)(我的意思是我们测量具体调用的时间“ REAL.method”,在这个意义上代理仍然有引用real)。最奇怪的是,虽然方法doSomething比较简单,但是耗时要长很多,请解释一下为什么?第一次调用创建的对象时会发生什么样的熨斗预热?毕竟,类已经加载,对象已经在堆上。第一次通话花费的时间是多少?即使somethingElse方法“更长”,为什么后续调用要快得多?
在输出中,我们看到我在自己
doSomething()身上花费了 ~ 265,000 ns
somethingElse()~ 45,000 ns
import java.lang.reflect.*;
import static lib.Printer.*;
interface Interface {
void doSomething();
void somethingElse(String arg);
}
class RealObject implements Interface {
@Override
public void doSomething() {
print("doSomething");
}
@Override
public void somethingElse(String arg) {
print("Something else: " + arg);
}
}
class DynamicProxyHandler implements InvocationHandler {
private Object proxied;
public DynamicProxyHandler(Object proxied) {
this.proxied = proxied;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("**** proxy: " + proxy.getClass() + ", method: " + method + ", args: " + args);
if (args != null)
for (Object arg : args)
System.out.println(" " + arg);
Object o;
long st = System.nanoTime();
o = method.invoke(proxied, args);
System.out.println(" spent: " + (System.nanoTime() - st));
return o;
}
}
class SimpleDynamicProxy {
public static void consumer(Interface iface) {
iface.doSomething();
iface.somethingElse("bonobo");
}
public static void main(String[] args) {
RealObject real = new RealObject();
consumer(real);
// Замеряем время:
Interface proxy = (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(),
new Class[] { Interface.class }, new DynamicProxyHandler(real));
consumer(proxy);
}
}
该方法
doSomething需要更长的时间来调用,因为这是第一次使用反射调用该方法。此时,作为第一次调用构造函数或静态方法的结果,加载了为此所需的类文件(缓存了 MB 的内容)。您可以通过在第一次调用之前和之后jmap从您的程序代码调用该实用程序来验证这一点。Method.invoke在这种情况下,我们将调用哪个方法并不重要。例如,让我们采取Object.toString.在代码的原始版本中,我们得到第一种方法比第二种方法花费的时间多 2 倍。现在让我们添加一个带有额外调用的行:
并且方法的执行时间变得大致相同。