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 jakarta.servlet.ServletContextEvent;
14  import jakarta.servlet.ServletContextListener;
15  import jakarta.servlet.annotation.WebListener;
16  
17  import javax.imageio.ImageIO;
18  
19  import org.slf4j.Logger;
20  import org.slf4j.LoggerFactory;
21  
22  /**
23   * Prevents a classloader leak.
24   *
25   * <p>
26   * As suggested by: <a href="https://cdivilly.wordpress.com/2012/04/23/permgen-memory-leak/">Colm
27   * Divilly</a>
28   */
29  @WebListener
30  public class AwtAppContextClassloaderListener implements ServletContextListener {
31  
32    /** The Constant logger. */
33    private static final Logger logger =
34        LoggerFactory.getLogger(AwtAppContextClassloaderListener.class);
35  
36    /**
37     * Forces the {@code sun.awt.AppContext} singleton to be created and initialized when the context
38     * is initialized.
39     *
40     * @param sce the event containing the context being initialized
41     */
42    @Override
43    public void contextInitialized(ServletContextEvent sce) {
44      try {
45        final ClassLoader active = Thread.currentThread().getContextClassLoader();
46        try {
47          // Find the root classloader
48          ClassLoader root = active;
49          while (root.getParent() != null) {
50            root = root.getParent();
51          }
52          // Temporarily make the root class loader the active class loader
53          Thread.currentThread().setContextClassLoader(root);
54          /*
55           * Forces the sun.awt.AppContext singleton to be created and initialized. Call
56           * ImageIO.getCacheDirectory() to avoid direct call to Oracle JVM internal class
57           * sun.awt.AppContext. Same solution as in
58           * org.apache.catalina.core.JreMemoryLeakPreventionListener which is optional on Tomcat.
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  }