Created
November 18, 2013 20:02
-
-
Save jnehlmeier/7534390 to your computer and use it in GitHub Desktop.
Utility class used in ServletContextListener to fix various memory leaks in application servers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import javax.imageio.ImageIO; | |
import java.awt.*; | |
import java.lang.reflect.Field; | |
import java.util.logging.LogManager; | |
public class LeakProtection { | |
private static final Logger logger = LoggerFactory.getLogger(LeakProtection.class); | |
private static Field inheritableThreadLocalsField; | |
static { | |
try { | |
inheritableThreadLocalsField = Thread.class.getDeclaredField("inheritableThreadLocals"); | |
inheritableThreadLocalsField.setAccessible(true); | |
} catch (NoSuchFieldException e) { | |
logger.warn("'inheritableThreadLocals' not found in Thread.class. " + | |
"LeakProtection.newThread() und LeakProtection.clearInheritableThreadLocals() won't work.", e); | |
} | |
} | |
public static void fixJavaUtilLogLeaks() { | |
LogManager lm = LogManager.getLogManager(); | |
logger.info("Memory Leak fixed: LogManager ({})", lm); | |
} | |
/** | |
* Fixes various AWT leaks that might occur in application servers | |
*/ | |
public static void fixAwtLeaks() { | |
// code executed in a custom thread to make sure no inheritableThreadLocals will leak into | |
// threads that might be created by AWT and are out of our control (e.g. 2D Disposer thread) | |
Runnable runnable = new Runnable() { | |
@Override | |
public void run() { | |
//Replace WebAppClassLoader with system ClassLoader while executing this Runnable | |
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader()); | |
try { | |
sun.awt.AppContext context = sun.awt.AppContext.getAppContext(); | |
logger.info("Memory Leak fixed: sun.awt.AppContext initialized. ({})", context); | |
Class.forName("sun.java2d.Disposer").newInstance(); | |
logger.info("Memory Leak fixed: Java2D Disposer Thread initialized."); | |
ImageIO.setUseCache(false); | |
ImageIO.getCacheDirectory(); | |
logger.info("Memory Leak fixed: ImageIO System initialized."); | |
Font arial = Font.decode( "Arial-BOLD-18" ); | |
String font = arial.toString(); | |
logger.info("Memory Leak fixed: Font System initialized. ({})", font); | |
GraphicsEnvironment g = GraphicsEnvironment.getLocalGraphicsEnvironment(); | |
logger.info("Memory Leak fixed: GraphicsEnvironment initialized. ({})", g); | |
Toolkit t = Toolkit.getDefaultToolkit(); | |
if(t != null) { | |
t.getSystemEventQueue(); | |
} | |
logger.info("Memory Leak fixed: DefaultToolkit initialized. ({})", t); | |
} catch (Throwable e) { | |
logger.warn("Unexpected Exception occurred during memory leak fixing. Memory leaks might be possible.", e); | |
} | |
} | |
}; | |
Thread t = newThread("LeakProtection - Fix AWT leaks", runnable); | |
t.start(); | |
try { | |
t.join(); | |
} catch (InterruptedException e) { | |
logger.warn("Thread '{}' interrupted!", t.getName(), e); | |
} | |
} | |
/** | |
* Sets the 'inheritableThreadLocals' field of Thread.class to null for a given target. | |
*/ | |
public static void clearInheritableThreadLocals(Thread target) { | |
if(inheritableThreadLocalsField == null) { | |
return; | |
} | |
try { | |
inheritableThreadLocalsField.set(target, null); | |
} catch (Throwable e) { | |
logger.warn("Can not set Thread.inheritableThreadLocals to NULL. {}", target.getName(), e); | |
} | |
} | |
/** | |
* Creates a new thread that does not have any inheritableThreadLocals. | |
* | |
* @param threadName name of the thread | |
* @param target runnable to execute | |
* @return new thread without any inheritableThreadLocals | |
*/ | |
public static Thread newThread(String threadName, Runnable target) { | |
Thread t = new Thread(target, threadName); | |
clearInheritableThreadLocals(t); | |
return t; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment