如何在webapp中捕获内存泄漏?

时间:2017-02-21 20:15:38

标签: java sqlite tomcat jsf primefaces

我的网络应用中存在内存泄漏问题。当被少数人使用时,应用程序在大约7小时后内存不足。

这就是我的应用的工作原理:

  • 用户登陆登录页面,登录,成功登录用户POJO对象被添加到会话地图中,如下所示: FacesContext.getCurrentInstance()。getExternalContext()。getSessionMap()。put(" user",user);
  • 在每个后续页面请求中,AuthFilter会检查是否有"用户"会话映射中的对象并允许进一步访问;
  • 我有SessionScoped bean(LoggedUserBean),它保存用户信息(以及登录后初始化的权限),因为它经常被访问。 LoggedUserBean注入大多数bean,也可以直接从XHTML页面访问。
  • 还有一些其他SessionScoped bean应该保持其状态。大多数bean都注入了DAO对象(@Named,默认@Dependent)。很少有bean和所有DAO对象都注入了DatabaseConnection对象(@Named与在构造函数中创建的数据源如下: dataSource = (DataSource) new InitialContext().lookup("java:comp/env/" + "jdbc/MyResName");)。
  • Primefaces对话框中很少有(@Named)验证器验证动态创建的组件树:

<h:inputHidden value="true"> <f:validator binding="#{someValidator}"/> </h:inputHidden>

并且实现是这样的:

@Named
public class SomeValidator extends ValidatorCommon implements Validator {

    private final static Logger LOGGER = Logger.getLogger(SomeValidator.class);

    @Override
    public void validate(FacesContext fc, UIComponent uic, Object o) throws ValidatorException {...}
{...}

这是我的context.xml:

<Resource auth="Container"
          driverClassName="org.sqlite.JDBC"
          maxTotal="1"
          maxIdle="1"
          minIdle="1"
          maxWaitMillis="5000"
          initialSize="1"
          name="jdbc/MyResName"
          type="javax.sql.DataSource"
          removeAbandonedOnBorrow="true"
          removeAbandonedTimeout="5"
          logAbandoned="true"
          validationQuery="SELECT 1"
          url="jdbc:sqlite:path/to/db/db.db">
</Resource>

我已经使用VisualVM创建了堆转储,并且MAT显示此漏洞可疑(https://i.imgur.com/wGsnyt5.png):http://i.imgur.com/wGsnyt5.png

据我所知,每次请求/访问时都会创建RequestScoped bean,而从特定会话的容器中检索SessionScoped(或者如果它不存在则创建),即使我之间存在交叉引用豆,这一切都应该工作得很好。

这是我实际需要帮助的地方:如何分析这些泄漏的来源?肯定有一些东西不允许释放内存,但我怎么能找到它呢?

我使用的是Primefaces 6.0,Apache Tomcat(TomEE)/8.5.3(7.0.1),JDK 1.7.0_80-b15,Mojarra 2.2.6,sqlite-jdbc 3.14.2.1。

如果需要任何其他文件,请告诉我们,我会修改此帖子以添加它们。

Web.xml中:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee" 
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         id="WebApp_ID" version="3.0">

    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>

    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
    </context-param>

    <context-param>
        <param-name>primefaces.FONT_AWESOME</param-name>
        <param-value>true</param-value>
    </context-param>

    <resource-env-ref>
        <resource-env-ref-name>jdbc/MyResName</resource-env-ref-name>
        <resource-env-ref-type>javax.sql.DataSource</resource-env-ref-type>
    </resource-env-ref>

    <!-- Welcome page -->
    <welcome-file-list>
        <welcome-file>pages/pub/login.xhtml</welcome-file>
    </welcome-file-list>

    <!-- Error pages -->
    <error-page>
        <exception-type>javax.faces.application.ViewExpiredException</exception-type>
        <location>/pages/pub/err/expired.xhtml</location>
    </error-page>

    <!-- Prevents comments in xhtml pages to be placed in final html and evaluated -->
    <context-param>
        <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
        <param-value>true</param-value>
    </context-param>

    <!-- JSF mapping -->
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>

    <!-- Primefaces theme -->
    <context-param>
        <param-name>primefaces.THEME</param-name>
        <param-value>cupertino</param-value>
    </context-param>

    <session-config>
        <session-timeout>120</session-timeout>
    </session-config>

    <filter>
      <filter-name>forceUTF8CharSet</filter-name>
      <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
      <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
      </init-param>
    </filter>

    <filter-mapping>
      <filter-name>forceUTF8CharSet</filter-name>
      <url-pattern>*</url-pattern>
    </filter-mapping>

    <mime-mapping>
        <extension>ttf</extension>
        <mime-type>application/font-sfnt</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>woff</extension>
        <mime-type>application/font-woff</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>woff2</extension>
        <mime-type>application/font-woff2</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>eot</extension>
        <mime-type>application/vnd.ms-fontobject</mime-type>
    </mime-mapping>
        <mime-mapping>
        <extension>eot?#iefix</extension>
        <mime-type>application/vnd.ms-fontobject</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>svg</extension>
        <mime-type>image/svg+xml</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>svg#latobold</extension>
        <mime-type>image/svg+xml</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>svg#latoblack</extension>
        <mime-type>image/svg+xml</mime-type>
    </mime-mapping>
        <mime-mapping>
        <extension>svg#latolight</extension>
        <mime-type>image/svg+xml</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>svg#latoregular</extension>
        <mime-type>image/svg+xml</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>svg#fontawesomeregular</extension>
        <mime-type>image/svg+xml</mime-type>
</mime-mapping>
</web-app>

2 个答案:

答案 0 :(得分:0)

可能首先尝试使用TomEE 7.0.2。如果它没有帮助,那么尝试调试WebContext map以检查哪些CDI bean没有被释放,那么你将能够知道谁(tomee,tomcat,primefaces,other)负责它并检查你是否可以解决它

答案 1 :(得分:0)

我设法解决了我的问题。

我的问题不在于我的任何bean,处理程序,验证程序,身份验证机制等。真正的问题是我在pom.xml中包含了两个库:

<dependency>
    <groupId>com.sun.faces</groupId>
    <artifactId>jsf-api</artifactId>
    <version>2.2.6</version>
</dependency>
<dependency>
    <groupId>com.sun.faces</groupId>
    <artifactId>jsf-impl</artifactId>
    <version>2.2.6</version>
</dependency>

我不太清楚TomEE在遇到两个独立的实现时会如何表现(TomEE自己及以上),但似乎有些东西阻止了对某些资源的引用,导致WebContext的大小总是增长(它持有所有参与请求处理的对象 - 跨多个页面。或者这可能是jsf实现中的一个错误?

如果有人能够解释实际发生的事情,那么我会接受这样的答案来解决我的问题。在那之前,这个答案(没有太多推理)是解决方案。