Open orange-buffalo opened 9 years ago
Yeah man, I've faced this problem too. Guys 'TestNG' can we expect to get some fix for this?
Same problem here...
I'm doing it to solve problems with Arquillian:
@WebListener
public class ArquillianTestCleanerListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
try {
Field field = Class.forName("org.testng.TestNG").getDeclaredField("m_instance");
field.setAccessible(true);
field.set(null, null);
} catch (Throwable e) {
//ignore
}
try {
Field field = Class.forName("org.testng.Reporter").getDeclaredField("m_currentTestResult");
field.setAccessible(true);
ThreadLocal threadLocal = (ThreadLocal)field.get(null);
field.set(null, null);
field = Thread.class.getDeclaredField("threadLocals");
field.setAccessible(true);
Method removeMethod = null;
for (Thread t : Thread.getAllStackTraces().keySet()) {
Object threadLocalsMapObject = field.get(t);
if (threadLocalsMapObject != null){
if (removeMethod == null){
removeMethod = threadLocalsMapObject.getClass().getDeclaredMethod("remove", ThreadLocal.class);
removeMethod.setAccessible(true);
}
removeMethod.invoke(threadLocalsMapObject, threadLocal);
}
}
} catch (Throwable e) {
//ignore
}
try {
Field field = Class.forName("org.jboss.arquillian.testenricher.cdi.container.CDIExtension")
.getDeclaredField("beanManager");
field.setAccessible(true);
field.set(null, null);
} catch (Throwable e) {
//ignore
}
}
}
Yeap, this is a good workaround, thanks!
Hi, new version (one more Threadlocal field cleanup):
@WebListener
public class ArquillianTestCleanerListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
cleanStaticField("org.testng.TestNG", "m_instance");
cleanStaticField("org.jboss.arquillian.testenricher.cdi.container.CDIExtension", "beanManager");
cleanStaticThreadLocalField("org.testng.Reporter", "m_currentTestResult");
cleanStaticThreadLocalField("org.jboss.arquillian.testng.State", "caughtExceptionAfter");
}
private void cleanStaticField(String className, String fieldName) {
try {
Field field = Class.forName(className).getDeclaredField(fieldName);
field.setAccessible(true);
field.set(null, null);
} catch (Throwable e) {
//ignore
}
}
private void cleanStaticThreadLocalField(String className, String fieldName) {
try {
Field field = Class.forName(className).getDeclaredField(fieldName);
field.setAccessible(true);
ThreadLocal threadLocal = (ThreadLocal) field.get(null);
field.set(null, null);
field = Thread.class.getDeclaredField("threadLocals");
field.setAccessible(true);
Method removeMethod = null;
for (Thread t : Thread.getAllStackTraces().keySet()) {
Object threadLocalsMapObject = field.get(t);
if (threadLocalsMapObject != null) {
if (removeMethod == null) {
removeMethod = threadLocalsMapObject.getClass().getDeclaredMethod("remove", ThreadLocal.class);
removeMethod.setAccessible(true);
}
removeMethod.invoke(threadLocalsMapObject, threadLocal);
}
}
} catch (Throwable e) {
//ignore
}
}
}
Hi! Could you please clarify which version contains this fix? I couldn't find this code in 6.8.17
Hi @orange-buffalo , this is a code to put in your application, not a TestNG code.
Ah, okay, thanks :)
Currently
org.testng.Reporter#m_currentTestResult
is not cleared after test execution in case whenSkipException
was thrown. This causes memory leaks in some cases, for instance when using Arquillian (thread local contains reference to deployment module, for each test).