4

我目前想知道 JVM 中用于加载从未使用过的额外类的实际开销是多少。

我们有代码迭代类路径中的所有类以找到实现某个接口的类,然后我们加载它们。

这允许将自定义类简单地放在目录中,然后加载和注册它们。

副作用是我们点击了类路径中的每个类,导致类加载。对 JVM 内存有什么影响?

简单地加载类会影响内存吗?

4

5 回答 5

4

像往常一样,我建议针对您的特定情况进行测量。

话虽如此,我不确定我是否建议扫描整个类路径。如果您不控制类路径(它是您的客户的或类似的),他们可能会向其中添加任何内容,并且您的进程将扫描他们放入类路径中的任何内容(可能与您的应用程序无关)。

我建议您仅指定可以将类上传到的某些目录/存储库,这样您将限制类路径扫描并减少无意中拾取您不打算使用的内容的机会。

于 2009-06-10T09:01:49.883 回答
2

如果您使用单独的 ClassLoader 来加载这些类,并且非常小心不要创建对这些类或它们的实例的任何引用,那么当 ClassLoader 符合垃圾收集条件时,这些类也会这样做。

因此,您可以通过使用单独的 ClassLoader 执行 2 次传递来避免不必要地阻塞 PermGen 空间:一次加载所有类并识别您想要保留的类,另一次实际使用它们。

于 2009-06-10T09:14:48.500 回答
1

以这种方式使用 ClassLoaders 不会产生意想不到的副作用吗?比如运行静态初始化程序等等。

您可以使用ServiceLoader机制,但如果不适合,您可以在不使用 ClassLoaders 的情况下检查类 - BCELASM等字节操作库可用于仅检查类。

于 2009-06-10T09:49:48.180 回答
0

是的,这会强制 VM 加载类文件并检查它(这可能是一个性能问题)。此外,如果您使用的是 Sun VM,那么这些类将永远保留在内存中。Sun VM 将类放在所谓的“PermGen”空间中,除非您指定特殊选项,否则该空间永远不会被垃圾收集。

所以这通常是一个坏主意,但有两个简单的解决方法:

  1. 检查类的名称(文件名)。在名称中重复接口的名称,这样您就可以很容易地注意到您必须加载哪些内容和不加载哪些内容。

  2. 使用两个目录。一个包含普通类,另一个包含您想要始终加载的所有类。

于 2009-06-10T09:02:29.010 回答
0

一个“远方”的建议:

你能做同样的事情但不实际使用虚拟机吗?类文件规范已记录在案,您不能编写自己的应用程序来读取类文件并确定它们是否实现了您的接口/无论是否实际加载它们?

这将使您能够扫描任何目录,但无需担心加载类或静态初始化程序或类似的东西。

于 2009-06-10T17:44:01.030 回答