什么导致JBoss上的PermGen OutOfMemoryError?

在JBoss中,PermGen OutOfMemoryError的根本原因是什么?

我在我的开发环境中运行JBoss AS 4.2.2,并且这在重新部署我的Web应用程序很多次之后发生。

Christian Vest Hansen的博客给出了很多有帮助 JVM选项,但是并没有完全解决这个问题:

-XX:+UseConcMarkSweepGC -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=128m 

    如上所述,您可能正在经历泄漏的class级装载机。 由于某种原因,你的类没有被卸载。 这可能有两个原因

    • 所述类的对象仍然存在于堆上,对象总是引用它们的类,或者
    • 类加载器被引用某处,无论出于何种原因,类加载器引用它们的类,以便不加载它们两次

    这个问题没有全面的解决scheme。 一个有用的工具可以帮助你find根本原因,就是Eclipse Memory Analyzer工具 ,你可以将它应用到JVM的堆转储(你可以使用-XX:+ HeapDumpOnOutOfMemoryError选项在OOM上启用堆转储)。 也许从Web应用程序开始寻找java.lang.Class对象,看看它们为什么保持活着。 不幸的是,PermGen通常不是JVM堆转储的一部分,所以你只能尝试在堆的其余部分find相关的工件(如果没有错误,类对象不存储在PermGen中,只有实际的字节代码是纠正我,如果我错了)。

    HTH。

    编辑:
    Dave Cheney在评论中build议java.lang.Class对象确实是PermGen的一部分,并且不包含在正常的热点堆转储中。 除非你有一个JVM把这个信息写入堆转储,否则你需要一个不同的方法。 你仍然可以查找你的对象的实例,但是如果你正在泄漏类/类加载器(它们都不幸意味着彼此),似乎你需要寻找其他迹象(来自JBoss的元数据对象等)。

    其根本原因是对被丢弃的类的引用,它们在类加载器外部泄漏,从而阻止JVM从这个类中卸载这些类。 您使用的这些标志可能会导致JVM积极地清除无法加载的类,但不能解决潜在的问题。

    这里有一个很好的,非常复杂的解释

    PermGen OutOfMemory错误的原因是应用程序重新部署。 根本原因是从重新部署中泄露了PermGen中的Class对象。

    当然,解决方法是在重新部署一定数量后重新启动JVM。

    这是一个非常难以完全解决的问题,虽然在进行一些调查之后,你往往可以做出很大的改进。 这里是你开始的地方:当你的Web应用程序停止时,确保:

    • 您开始的所有线程都停止
    • 您启动的所有 ThreadPool都将closures
    • 所有你可以释放的静态引用被释放

    这些是可能导致一个Class对象被困在PermGen中的一些事情。

    另外,请注意,并非所有的JVM(或所有版本的JVM)都将在PermGen中使用GC Class对象。 如果您正在运行JVM或JVM的版本,而JVM不会在PermGen中使用GC Class对象,那么您唯一的select是在重新部署一定数量后重新启动JVM。 鉴于您提到的JVM选项,这可能不适用于您。