有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

性能Java类加载运行极慢?

我正在尝试加载一个java。动态地初始化文件并通过反射调用它

我有一门课叫Foo;它有一个空构造函数和一个名为doit()的方法,该方法接受一个字符串参数并返回一个字符串。它还反转字符串

这是我的密码:

    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);

正如所料,这会打印出“你好,世界!”。但是,大约需要30秒才能完成。我知道反射很慢,但我希望是10毫秒左右

我将Eclipse与JRE 1.6.0_13一起使用,并运行Windows Vista

我做错了什么

谢谢

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

编辑:我已将代码放入循环中;slow函数以某种方式得到优化,在第一个循环中只需要30秒

编辑:我找到了解决方案

而不是:

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

我把它改成:

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

现在它工作得很好。我不知道为什么它会起作用,但我不明白我(和其他5个人)怎么会错过它。现在我觉得自己很笨


共 (6) 个答案

  1. # 1 楼答案

    您是否可以将Foo放在默认类路径中,这样您就可以使用如下内容:

    ClassLoaderTest.class.getClassLoader()
    

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

    this.getClass().getClassLoader()`  
    

    这两种方法中的任何一种都可以节省实例化新类加载器的时间

    但我不知道这是否会对你有帮助(你必须分析),而且反射总是会明显地慢一些。这是绕不开的。当然,出于这一原因和其他原因,在生产中应该尽量少用它

    编辑:由于loadClass占用了大部分时间,可能是C:\jtest比较混乱。你可以试着把Foo放进去。在目录中单独初始化并将其用作URL。当然,第二次更快的原因是已经加载了Foo

  2. # 2 楼答案

    你的代码没有问题。。。我能在不到一秒钟内编译你的程序。我正在Vista Business上运行Java1.6.11

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

  3. # 3 楼答案

    30秒后,您应该能够“评测”代码,并准确地看到问题所在(加载类、创建实例、查找方法等等)

    因为它需要30秒(而不是更小的时间,大约10毫秒),所以您可以在代码的每一行之间使用System.out.println(new Date());

    我猜你会发现是装载机。loadClass(String)花费了很长时间——我怀疑您会发现您要么拥有很长的类路径,要么拥有包含某种网络资源的类路径

  4. # 4 楼答案

    当您创建实例时,可能会导致加载许多其他类,其中一些类具有静态初始值设定项,这些初始值设定项会执行耗时较长的操作。将此代码放入循环中,然后查看后续对象创建的成本

    编辑:很酷,根据您的分析,这听起来像是您正在接近根本原因。另一个要考虑的是,如果你使用的图书馆有很大的启动成本。我使用iBatis来管理我们与Oracle的交互,当它第一次启动时,它读取一组XML文件并处理其中的查询模式。有一个明显的滞后。听到你的发现会很有趣,但你可能会认为一次性成本是可以承受的

  5. # 5 楼答案

    有关您的信息: 也许对你来说有点晚了,但我偶然发现了同样的问题并找到了这篇文章

    看起来//正在强制进行远程搜索,如果您使用-verbose:class运行,则加载了UnknownHostException,因此必须在类加载期间在内部抛出该异常

    我尝试了以下方法:

    URL=新URL(“file://localhost/C:/jtest/”

    这项工作(几乎)和你的单斜杠解决方案一样快

  6. # 6 楼答案

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