View Javadoc
1   /*
2    * Licensed under the GPL License. You may not use this file except in compliance with the License.
3    * You may obtain a copy of the License at
4    *
5    *   https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
6    *
7    * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
8    * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
9    * PURPOSE.
10   */
11  package psiprobe;
12  
13  import javax.imageio.ImageIO;
14  import javax.servlet.ServletContextEvent;
15  import javax.servlet.ServletContextListener;
16  import javax.servlet.annotation.WebListener;
17  
18  import org.slf4j.Logger;
19  import org.slf4j.LoggerFactory;
20  
21  /**
22   * Prevents a classloader leak.
23   *
24   * <p>
25   * As suggested by: <a href="https://cdivilly.wordpress.com/2012/04/23/permgen-memory-leak/">Colm
26   * Divilly</a>
27   */
28  @WebListener
29  public class AwtAppContextClassloaderListener implements ServletContextListener {
30  
31    /** The Constant logger. */
32    private static final Logger logger =
33        LoggerFactory.getLogger(AwtAppContextClassloaderListener.class);
34  
35    /**
36     * Forces the {@code sun.awt.AppContext} singleton to be created and initialized when the context
37     * is initialized.
38     *
39     * @param sce the event containing the context being initialized
40     */
41    @Override
42    public void contextInitialized(ServletContextEvent sce) {
43      try {
44        final ClassLoader active = Thread.currentThread().getContextClassLoader();
45        try {
46          // Find the root classloader
47          ClassLoader root = active;
48          while (root.getParent() != null) {
49            root = root.getParent();
50          }
51          // Temporarily make the root class loader the active class loader
52          Thread.currentThread().setContextClassLoader(root);
53          /*
54           * Forces the sun.awt.AppContext singleton to be created and initialized. Call
55           * ImageIO.getCacheDirectory() to avoid direct call to Oracle JVM internal class
56           * sun.awt.AppContext. Same solution as in
57           * org.apache.catalina.core.JreMemoryLeakPreventionListener which is optional on Tomcat
58           * 1.7.0_02 or greater.
59           */
60          ImageIO.getCacheDirectory();
61        } finally {
62          // restore the class loader
63          Thread.currentThread().setContextClassLoader(active);
64        }
65        logger.info("AwtAppContextClassloaderListener Initialized");
66      } catch (Exception e) {
67        logger.error("Failed to address PermGen leak.", e);
68      }
69    }
70  
71    @Override
72    public void contextDestroyed(ServletContextEvent sce) {
73      // Not Implemented
74    }
75  
76  }