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           * 1.7.0_02 or greater.
60           */
61          ImageIO.getCacheDirectory();
62        } finally {
63          // restore the class loader
64          Thread.currentThread().setContextClassLoader(active);
65        }
66        logger.info("AwtAppContextClassloaderListener Initialized");
67      } catch (Exception e) {
68        logger.error("Failed to address PermGen leak.", e);
69      }
70    }
71  
72    @Override
73    public void contextDestroyed(ServletContextEvent sce) {
74      // Not Implemented
75    }
76  
77  }