JBoss Weld + java.lang.OutOfMemoryError:PermGen 空间

Posted

技术标签:

【中文标题】JBoss Weld + java.lang.OutOfMemoryError:PermGen 空间【英文标题】:JBoss Weld + java.lang.OutOfMemoryError: PermGen space 【发布时间】:2011-07-28 23:16:29 【问题描述】:

我刚刚切换到 Weld 以使用 CDI JSF 2 Beans + 对话范围。

这是我的 Maven 依赖项:

    <dependency>
        <groupId>org.jboss.weld.servlet</groupId>
        <artifactId>weld-servlet</artifactId>
        <version>1.0.1-Final</version>
        <type>jar</type>
        <scope>compile</scope>
    </dependency>

这是我的 web.xml 中的条目:

<listener>
  <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>

我立即注意到的一件事是我只需要重新加载我的 tomcat 7 大约 2 次,java.lang.OutOfMemoryError: PermGen space 就会出现在 catalina.out 日志文件中。

在使用 Weld 之前,我可以在没有 java.lang.OutOfMemoryError 的情况下安全地重新加载我的 tomcat 7 超过 10 次。我认为在 catalina.sh 中增加我的 Xmx 选项会有所帮助,但在我的经验中并没有。 JAVA_OPTS=-Xmx1024m

这正常吗?

【问题讨论】:

这当然不正常。但是除非您在代码中进行一些挖掘并找到消耗内存的部分,否则绝对不可能说是您的代码还是实现本身...... @jan groth:我不认为这是我的代码,因为它是一个非常简单的测试项目,就像一个带有计数器的 jsf bean 等。在使用焊接之前,我使用的是 spring 或默认的 jsf托管 bean,一切都很好。 JAVA_OPTS=-Xmx1024m 不会增加 Permgen。 -XX:MaxPermSize=256m 会。 【参考方案1】:

当您想使用不是为此而设计的简单 servletcontainer 进入 Java EE 时,这确实是一个非常典型的错误;)

不,开个玩笑。 Tomcat 附带的默认 permgen 设置仅为 64MB。其中,Class 定义(即当您执行Class#forName() 时得到的任何东西)都存储在那里。粗略地说,Weld 扫描类路径中的每个单个 JAR 和类以查找注释,以便它可以以编程方式创建连接配置的内存映射(在注释之前,这通常由 XML 文件实现)。然而,在类路径中有很多类并加载了这么多类,在 permgen 空间中为 Tomcat 的热部署留下了很小的空间。

有几种方法可以解决这个问题。最合乎逻辑的方法是增加永久空间。您可以将其设置为 VM 参数。 256MB 是一个好的开始。

-XX:MaxPermSize=256m

如果您在 Eclipse 中使用 Tomcat,您需要通过双击 Servers 视图中的服务器条目,单击 打开启动配置 链接,单击 Arguments 选项卡,然后将其添加(空格分隔)到 VM Arguments 字段。

此外,您还可以强制 JVM 更节省地使用 permgen 空间。默认情况下,其中的对象很少被卸载。添加以下 VM 参数。

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

另见:

Tomcat Wiki - OutOfMemory errors

【讨论】:

【参考方案2】:

尝试设置 permsize:-XX:MaxPermSize=200m。您可能正在加载大量类定义,因此填满了永久代空间。

【讨论】:

【参考方案3】:

除了增加 PermGen 之外,您还应该从 Weld 扫描仪中排除不支持焊接的软件包。见这里:

20.1. Excluding classes from scanning and deployment

<?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://java.sun.com/xml/ns/javaee" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns:weld="http://jboss.org/schema/weld/beans" 
         xsi:schemaLocation="
            http://java.sun.com/xml/ns/javaee http://docs.jboss.org/cdi/beans_1_0.xsd
            http://jboss.org/schema/weld/beans http://jboss.org/schema/weld/beans_1_1.xsd">

      <weld:scan>

          <!-- Don't deploy the classes for the swing app! -->
          <weld:exclude name="com.acme.swing.**" />

          <!-- Don't include GWT support if GWT is not installed -->
          <weld:exclude name="com.acme.gwt.**">
              <weld:if-class-available name="!com.google.GWT"/>
          </weld:exclude>

          <!--
              Exclude classes which end in Blether if the system property verbosity is set to low
              i.e.  java ... -Dverbosity=low            
          -->        
          <weld:exclude pattern="^(.*)Blether$">
              <weld:if-system-property name="verbosity" value="low"/>
          </weld:exclude>

         <!--
               Don't include JSF support if Wicket classes are present, and the viewlayer system
               property is not set
          -->
          <weld:exclude name="com.acme.jsf.**">
              <weld:if-class-available name="org.apahce.wicket.Wicket"/>
              <weld:if-system-property name="!viewlayer"/>
          </weld:exclude>
      </weld:scan>

  </beans>

【讨论】:

以上是关于JBoss Weld + java.lang.OutOfMemoryError:PermGen 空间的主要内容,如果未能解决你的问题,请参考以下文章

org.jboss.weld.exceptions.DefinitionException:在payara / glassfish中部署时的WELD-001113

迁移到 Jboss EAP7 时出现 WELD 异常

WELD-001456参数bean不能为空

使用 CDI/Weld 注入通用 Bean

为什么我的拦截器在Weld SE单元测试中失败?

GlassFish - IllegalStateException