Java类加载运行速度极慢?

时间:2009-05-22 03:36:22

标签: java performance reflection

我正在尝试动态加载java .class文件并通过反射调用它。

我有一个名为Foo的课程;它有一个空的构造函数,并有一个名为doit()的方法,它接受一个String参数并返回一个String。它也会反转字符串。

这是我的代码:

    URL url = new URL("file://C:/jtest/");
    URLClassLoader loader = new URLClassLoader(new URL[]{url});
    Class<?> cl = loader.loadClass("Foo");
    Constructor<?> cons = cl.getConstructor((Class[])null);
    Object ins = cons.newInstance(new Object[]{});
    Method meth = cl.getDeclaredMethod("doit", String.class);
    Object ret = meth.invoke(ins, new Object[]{"!dlroW olleH"});
    System.out.println((String)ret);

正如预期的那样,它会打印出“Hello World!”。但是,完成需要大约 30秒。我知道反射很慢,但我希望它是10毫秒或者其他东西。

我正在使用Eclipse和JRE 1.6.0_13,而我正在运行Windows Vista。

我在这里做错了什么?

感谢。

编辑:我已经分析了代码,所有的时间都在第三行(loadClass())中使用。其他一切都会立即发生。

编辑:我把代码放在一个循环中;慢速函数以某种方式得到优化,仅在第一个循环上花费30秒。

编辑:我找到了解决方案。

而不是:

URL url = new URL("file://C:/jtest/");

我把它改为:

URL url = new URL("file:/C:/jtest/");

现在它完美无缺。我不知道它为什么会起作用,但我不知道我(以及其他5个人)是如何错过的。现在我感到愚蠢..

6 个答案:

答案 0 :(得分:6)

获取您的信息: 对你来说可能有点晚了,但我偶然发现了同样的问题并找到了这篇文章。

看起来//正在强制进行远程搜索,如果你使用-verbose:class运行,则会加载一个UnknownHostException,因此必须在类加载期间内部抛出它。

我尝试了以下内容:

网址url =新网址(“file:// localhost / C:/ jtest /”);

并且(几乎)与单一斜杠解决方案一样快。

答案 1 :(得分:5)

检查您的默认类路径。也许它指的是不可用的网络共享或类似的东西。

答案 2 :(得分:5)

在30秒时,您应该能够“分析”您的代码并查看问题的确切位置(在加载类时?在创建实例时?查找方法?等等?)

由于它需要30秒(而不是更小,大约10ms左右),你可以在代码的每一行之间使用System.out.println(new Date());

我怀疑你会发现它是load.loadClass(String)花了这么长时间 - 我怀疑你会发现你有一个很长的类路径,或者包含某种网络资源的类路径。 / p>

答案 3 :(得分:3)

当您创建实例时,它可能会导致许多其他类加载,其中一些类具有静态初始化程序,这些初始化程序会执行需要很长时间的事情。将此代码放在循环中,看看后续对象创建的成本。

编辑:很酷,基于您的分析,这听起来就像您已接近根本原因。另一件需要考虑的事情是,如果您使用的是具有较高启动成本的库。我使用iBatis来管理我们与Oracle的交互,当它第一次启动时,它会读入一堆XML文件并处理它们中的查询模式。有一个明显的滞后。听到你发现的东西很有意思,但你可能会认为一次成本是可以容忍的。

答案 4 :(得分:2)

您的代码没有任何问题......我能够在不到一秒的时间内编译您的程序。我在Vista Business上运行java 1.6.11。

也许你的public string doit(string arg)方法花了这么长时间。您可以尝试在不使用反射的情况下调用它来查看是否需要很长时间吗?尝试让doit()只返回您传入的参数(而不是反转字符),看看你的反转算法是否会减慢速度。

答案 5 :(得分:2)

您是否可以将Foo置于默认的CLASSPATH中,以便您可以使用以下内容:

ClassLoaderTest.class.getClassLoader()

,其中ClassLoaderTest是您正在运行的类。或者,如果您没有在静态上下文中运行,则提供:

this.getClass().getClassLoader()`  

其中任何一个都可以节省你实例化一个新的类加载器。

但是我不知道这是否会帮助你(你必须分析),并且反射总是明显变慢。没有解决这个问题。当然,出于这个原因和其他原因,它应该在生产中使用最少。

编辑:由于loadClass占用大部分时间,可能是C:\ jtest混乱。您可以尝试将Foo.class单独放在目录中并将其用作URL。当然,第二次更快的原因是Foo已经加载了。