Java: 如何找出一个类被加载的原因

12

我目前遇到的问题是,我有一个(部分)程序正在尝试加载一个类,但由于找不到该类而失败。查看堆栈跟踪,我无法看到虚拟机首先尝试加载此特定类的任何特定原因。是否有任何工具可以让我弄清楚为什么要加载特定的类?

提示: 我已经在JVM尝试加载类的确切点处(通过代理)得到了堆栈跟踪。但是,堆栈跟踪不包含行号。因此,我只知道哪个方法触发了类的加载,而不知道哪个语句。即使了解了语句,有时候也可能不够。单个语句可以以多种方式导致类被加载,因为有时虚拟机需要加载类的传递闭包的一部分。


1
我对Java不太熟悉,不过提供这个类的一个模拟,并在其中查看调用栈怎么样?反正如果在Java中可以的话。 - balpha
3
也许您可以在这里发布堆栈跟踪,因为有人可能会使用它来提供帮助。 - David Webb
这可能是验证器的副作用(请参阅Java Puzzlers)。但需要更多信息。 - Tom Hawtin - tackline
3个回答

25

使用-XX:+TraceClassLoading-XX:+TraceClassResolution标志运行您的程序。这将创建大量输出,看起来像以下内容:

[Loaded com.kdgregory.example.memory.PermgenExhaustion$MyClassLoader from file:/home/kgregory/Workspace/Website/programming/examples/bin/]
RESOLVE com.kdgregory.example.memory.PermgenExhaustion$MyClassLoader java.net.URLClassLoader
RESOLVE java.net.URLClassLoader java.lang.Class URLClassLoader.java:188

你需要跟踪一个特定类的解析消息链。或者更有可能的是,在程序尝试加载该类时,您会看到一个错误,其前面是加载它的类的解析消息。


结果正是我所需要的!让我的一天变得美好!非常感谢! - user66237
正是我所需要的。但是请注意,像我这样不细心的人:如果您盲目选择并复制参数“-XX:+TraceClassLoading”和“-XX:+TraceClassResolution”,请确保在使用此参数时不要复制它们之间的引号。我简直不敢相信我花了多长时间才弄清楚这个错误。 - James Moore
原来我真的需要一个变量 - -XX:-TraceClassLoadingPreorder。 - James Moore
@James - 很有趣。我一直在看那个字段的描述,试图弄清楚引用顺序与加载顺序的区别。这是因为JVM会缓存和聚合加载(我可以看到这种情况发生在多线程应用程序中)吗? - kdgregory
@kdgregory,我也有同样的怀疑。我刚刚尝试了这个标志,它给出了一个有用的答案。(使用该标志后,最近的加载确实是问题所在,没有使用该标志,我看到了一些来自java.*空间的类,但并不是问题所在。)如果类加载器认为可以通过另一个线程获得更好的性能,它是否会触发其他加载?这是我要调查的事情之一,但不幸的是它并不是非常重要。在我的情况下,我正在引入scala-library.jar中的东西,所以问题可能也出现在scala中。 - James Moore

5
你可以尝试使用类似JDepend的静态分析工具,查看哪些类引用了该类。

1
我已经做了,但依赖关系非常微妙。加载的类在当前执行的方法中没有被提及。它必须是当前方法中某个类型的接收器类的超类的字段类型的超类之类的东西...你懂我的意思。 - user66237

0

类加载器

如果是多个类加载器同时存在的环境(比如Web应用程序),你需要小心处理。请告诉我们这个应用程序的情况。

资源

告诉我们JAR包的位置(文件/目录结构)以及哪个类正在加载。你是使用Class.forName动态加载它吗?还是使用Spring或其他IOC框架?它是主类吗?

一些先前的测试(帮助我们)

也许你可以在main方法中使用Class.getResource()测试一些东西。如果你的类是foo.bar.Clazz,尝试使用Class.getResource("/foo/bar/Clazz.class")来查看是否返回有效结果。尝试使用加载失败的类所在的类来做同样的事情,看看它是否符合你的预期。


我已经在 JVM 尝试加载类(通过代理)的确切点处获得了堆栈跟踪。然而,堆栈跟踪不包含行号。因此,我只知道哪个方法触发了类的加载,而不知道是哪个语句。 - user66237
我的意图是查看引起问题的类加载器是否在预期的类加载器(比如说jar)上,还是在其他类加载器上。当然,如果你有多个类加载器... :( - helios

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接