题 PermGen空间是否减少了?


我想知道JVM是否正常卸载类以减少PermGen空间。所以我的问题在这里:

  1. Java类是否默认从JVM中卸载?
  2. 关闭Jar类加载器会从该jar中卸载所有加载的类吗?
  3. 应该使用哪些命令/方法来卸载类?

仅供参考,我确实在网上尝试了一些解决方案,但没有人回答我的问题。 (例如: JVM标志CMSClassUnloadingEnabled实际上做了什么?

PS:我指的是Java 6 + hibernate(类加载由hibernate处理)


12
2017-07-15 10:40


起源


你有什么样的申请? - Thilo
它随JVM版本和设置而变化。要卸载类,您必须至少删除对类的类加载器的所有引用,并且显然删除对类本身和类的任何实例的所有引用,包括由于堆栈调用帧引起的任何引用。更巧妙的是,您必须删除对引用已删除类的任何类的引用。 (这意味着您无法删除在“主线”代码中引用的类,例如, new SomeClass - 您必须以类名称作为String加载类。) - Hot Licks
@Thilo我的应用程序包括动态加载jar提供的类。用户可以“在运行时”更改此jar,并在更改一些jar后,应用程序达到 OutOfMemoryError: PermGen space 因为旧类(来自被忽视的jar)永远不会被卸载。 - Adel Boutros


答案:


Hibernate加载所有 Entity 在内存中的类时 SessionFactory 开始。另一方面,实体的加载由 Hibernate 在一个 lazy 方式,只在需要时。

可以通过卸载类 GC 当。。。的时候 JVM 需要记忆。 实体istances也是垃圾收集,但是,与任何其他对象一样,只有当没有更多的引用指向它们时。换一种说法 Entity 如果是,则不能卸载 Hibernate 会议仍然开放。要卸载它们,您需要清除持久性上下文或关闭会话。


2
2017-07-15 14:25





摆脱加载类的唯一方法是允许JVM通过消除对此类加载器的所有引用来加载这些类的类加载器。当我们取消部署webapp时,这就是Web服务器中发生的情况。


3
2017-07-15 10:50



但Java 6中的问题是URLClassLoader从未真正取消引用Jar,因此类永远不会被卸载,不是吗? - Adel Boutros
在问题中检查我的PS - Adel Boutros
你如何在运行时更改jar?你必须先删除旧的类加载器及其所有类,然后才能卸载它们。 - Thilo
@AdelBoutros URLClassLoader仍可以引用类。如果对类的唯一引用来自它们的类加载器并且没有对类加载器的引用,则这形成了一个“孤岛”,垃圾收集器可以很好地处理它。 - Brandon
@Thilo据我所知,hibernate在内部处理类加载 - Adel Boutros


目前,默认情况下正在收集永久代。

永久世代由一个空间组成,但没有自己的收集器。相反,这个空间是作为老一代的一部分收集的。

根据 这个visualgc 页。

在旧的JVM中,您可以使用 -XX:+CMSPermGenSweepingEnabled 旗。

当AFAIK类未从任何ClassLoader引用时,它们将被卸载。

java.lang.OutOfMemoryError: PermGen space 错误是由类加载器中的内存泄漏引起的。取消部署/重新部署Web应用程序时的常见问题。


3
2017-07-15 10:56





假设你在谈论HotSpot,即Oracle / Sun JVM。

  1. 如果没有引用它们。请注意,所有类都引用了它们的类加载器,反之亦然,并且所有对象都引用了它们的类。
  2. 也许。你是什​​么意思“靠近”?
  3. 使用选项启动JVM -XX:+UseConcMarkSweepGC 和 -XX:+CMSClassUnloadingEnabled。这将允许卸载未使用的类,即使它们的类加载器仍然存在。

也可以看看 在java中卸载类?


2
2017-07-15 10:51



谢谢您的回答。在我的情况下,我必须动态附加一个Jar来加载新类。随着时间的推移,我得到了 OutOfMemoryError: PermGen space 我想知道为什么一旦罐子被忽视,来自旧罐子的类不会被卸载。 - Adel Boutros
如果你喜欢它,请upvote和/或接受它。 - OrangeDog