加载不需要的Java类

4

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

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

这使得自定义类可以简单地放入一个目录中,它们就会被加载和注册。

副作用是我们遍历了类路径中的每个类,导致这些类被加载。这对JVM的内存有什么影响吗?

仅仅加载类会对内存产生多大的影响吗?

5个回答

4
通常情况下,我建议您为特定情况进行测量。
话虽如此,我不确定是否建议扫描整个类路径。如果您无法控制类路径(例如: 客户的类路径等),则他们可以添加任何内容到其中,您的进程将扫描他们放入类路径中的任何文件(可能与您的应用程序无关)。
我建议您只指定可上传类的某些目录/存储库,这样您将限制类路径扫描并减少意外获取不想要文件的机会。

最好为客户可以实现的不同类型的类设置单独的位置。 - Neil Wightman

2
如果您使用单独的ClassLoader来加载这些类,并且非常小心,不要创建对这些类或其实例的任何引用,那么当ClassLoader变得适合进行垃圾回收时,这些类也会被回收。
因此,您可以通过使用两个独立的ClassLoader来避免不必要地占用PermGen空间:一次加载所有类并确定要保留的类,另一次实际使用它们。

1

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

你可以使用ServiceLoader机制,但如果那不适合你,你可以在不使用类加载器的情况下检查类 - 字节操作库,如BCELASM可以用来仅仅检查类。


是的,当它调用静态初始化程序时,这很痛苦。这在过去也导致了一些死锁 :( - Neil Wightman
是啊,谁知道在你无法控制的类中静态初始化器在做什么! - John Gardner

0

是的,这会强制虚拟机加载类文件并检查它(可能会影响性能)。此外,如果您使用的是Sun VM,则这些类将永久保存在内存中。Sun VM将类放置在所谓的“PermGen”空间中,除非指定特殊选项,否则永远不会进行垃圾回收。

因此,这通常是一个不好的主意,但有两个简单的解决方法:

  1. 检查类的名称(文件名)。在名称中重复接口的名称,这样您就可以轻松地注意到需要加载和不需要加载的内容。

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


1
不是真的 - 只有由系统类加载器加载的类才永远无法卸载。 - Michael Borgwardt
那么,为什么我在使用自带类加载器的Groovy进行开发时会遇到大量的OutOfPermGen错误? - Aaron Digulla

0
一个“非常超前”的建议:
你能不能不使用虚拟机来完成同样的事情呢?类文件规范已经有文档了,你能不能编写自己的应用程序来读取类文件,并找出它们是否实现了你的接口/任何内容,而不必加载它们?
这样就可以扫描任何目录,而不必担心加载类或静态初始化器等问题。

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