我的理解是 PermGen(在某种意义上)将类代码保存在内存中。通常我们有很多引用我们的类路径的 jar 文件。当一个 jar 文件包含在类路径中(比如在 tomcat 的 lib 目录中)时,所有这些 jar 的所有类是否都会自动加载到 PermGen 中?
在一个类似的问题中,一旦使用了一个 jar 文件的类,PermGen 是加载该 jar 文件中的所有类,还是只加载使用的类(然后在必要时加载其余的类文件)?
我的理解是 PermGen(在某种意义上)将类代码保存在内存中。通常我们有很多引用我们的类路径的 jar 文件。当一个 jar 文件包含在类路径中(比如在 tomcat 的 lib 目录中)时,所有这些 jar 的所有类是否都会自动加载到 PermGen 中?
在一个类似的问题中,一旦使用了一个 jar 文件的类,PermGen 是加载该 jar 文件中的所有类,还是只加载使用的类(然后在必要时加载其余的类文件)?
这在某种程度上取决于类加载器和 JVM 的实现——Java 虚拟机规范是这样说的:
该规范允许在何时发生链接活动(以及由于递归,加载)时实现灵活性,前提是尊重 Java 编程语言的语义,[...]
例如,实现可以选择单独解析类或接口中的每个符号引用,仅在使用时(延迟或延迟解析),或者在验证类时一次性解析它们(静态解析)。这意味着在某些实现中,在初始化类或接口之后,解析过程可能会继续。
在实践中,任何合理的实现都不应该仅仅因为加载了文件中的一个类就自动加载 JAR 文件中的所有内容,更不用说仅仅因为它在类路径上。
PermGen 是 HotSpot 的一个实现细节,Oracle 表示他们希望在未来摆脱它 [1]。它不是 Java (VM) 规范的一部分。只有加载的类最终会出现在 PermGen 中。通过链接显式地ClassLoader#loadClass
或隐式地通过链接。那应该只是使用的类(及其依赖项),除非有人明确加载所有类,例如。对它们进行反思。像 Spring 这样的框架避免了这种情况,而是扫描字节码。
一个很好的起点是VisualVM,它允许您观察加载的类 PermGen。
[1] JRockit 没有 PermGen,并且在最近的 HotSpot 版本中,字符串实习生池不再在 PermGen 中。
只有需要的类被加载并存储在 permgen 空间中。
JLS保证一个类在第一次被需要时被初始化——并且不早于它。但是,允许实现更早地执行加载和链接。