[
https://issues.apache.org/jira/browse/TOMEE-4192?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Georg Tsakumagos updated TOMEE-4192:
------------------------------------
Description:
The ApplicationComposers do not clear all references on release which could
result in very high memory consumption for tests if injected classes a heavy
weight. Having an project with many tests amplifies this problem enormous. An
analysis of heap dumps shows different implementations holding references.
{code:java|title=Example fat bean}
@ApplicationScoped
public class FatBean {
private static final long serialVersionUID = -5814319377355637770L;
private String payload;
public FatBean() {
super();
/*
* Big Memory Payload
*/
char[] array = new char[1024 * 1024 * 128];
Arrays.fill(array, '@');
this.payload = new String(array);
this.logger.info("Init FatProject Bean.");
}
}
{code}
Top overcome this bad behaviuour i've written an junit-extension to tear down
all references by reflection. I like to get rid of this hack.
{code:java|title=Teardown code}
/**
* Workaround for memory hogs in <em>OpenEJB</em>. Several components hold
* references via {@link ThreadLocal} {@link List} and other instances. They
are
* not cleared on shutdown and prevent the <em>GC</em> from cleanup.
*
* @param composer The Composer to dispose.
* @param testContext The TestContext.
*/
private void tearDown(ApplicationComposers composer, ExtensionContext
testContext) {
this.logger.info(LOG_INFO_DESTROY,
testContext.getTestInstanceLifecycle().orElse(null), composer);
try {
/*
* Reflection magic
*/
Field field =
composer.getClass().getDeclaredField(REFLECTION_FIELD_APPCONTEXT);
field.setAccessible(true);
AppContext context = (AppContext) field.get(composer);
/*
* Clear Lists.
*/
context.getWebContexts().clear();
context.getInjections().clear();
/*
* Another greedy hog
*/
try {
SystemInstance systemInstance = context.getSystemInstance();
if (null != systemInstance) {
field =
systemInstance.getClass().getDeclaredField(REFLECTION_FIELD_COMPONENTS);
field.setAccessible(true);
field.set(systemInstance, null);
}
} catch (final Throwable exception) {
this.logger.error(LOG_ERROR_TEAR_DOWN, exception);
}
/*
* Another greedy hog
*/
WebBeansContext webBeansContext = context.getWebBeansContext();
if (null != webBeansContext) {
try {
field =
webBeansContext.getClass().getDeclaredField(REFLECTION_FIELD_NOTIFICATIONMANAGER);
field.setAccessible(true);
field.set(webBeansContext, null);
} catch (final Throwable exception) {
this.logger.error(LOG_ERROR_TEAR_DOWN, exception);
}
try {
field =
webBeansContext.getClass().getDeclaredField(REFLECTION_FIELD_INTERCEPTORDECORATORPROXYFACTORY);
field.setAccessible(true);
field.set(webBeansContext, null);
} catch (final Throwable exception) {
this.logger.error(LOG_ERROR_TEAR_DOWN, exception);
}
}
} catch (final Throwable exception) {
this.logger.error(LOG_ERROR_TEAR_DOWN, exception);
}
}
{code}
was:
The ApplicationComposers do not clear all references on release which could
result in very high memory consumption for tests if injected classes a heavy
weight. An analysis of heap dumps shows different implementations holding
references.
{code:java|title=Example fat bean}
@ApplicationScoped
public class FatBean {
private static final long serialVersionUID = -5814319377355637770L;
private String payload;
public FatBean() {
super();
/*
* Big Memory Payload
*/
char[] array = new char[1024 * 1024 * 128];
Arrays.fill(array, '@');
this.payload = new String(array);
this.logger.info("Init FatProject Bean.");
}
}
{code}
Top overcome this bad behaviuour i've written an junit-extension to tear down
all references by reflection. I like to get rid of this hack.
{code:java|title=Teardown code}
/**
* Workaround for memory hogs in <em>OpenEJB</em>. Several components hold
* references via {@link ThreadLocal} {@link List} and other instances. They
are
* not cleared on shutdown and prevent the <em>GC</em> from cleanup.
*
* @param composer The Composer to dispose.
* @param testContext The TestContext.
*/
private void tearDown(ApplicationComposers composer, ExtensionContext
testContext) {
this.logger.info(LOG_INFO_DESTROY,
testContext.getTestInstanceLifecycle().orElse(null), composer);
try {
/*
* Reflection magic
*/
Field field =
composer.getClass().getDeclaredField(REFLECTION_FIELD_APPCONTEXT);
field.setAccessible(true);
AppContext context = (AppContext) field.get(composer);
/*
* Clear Lists.
*/
context.getWebContexts().clear();
context.getInjections().clear();
/*
* Another greedy hog
*/
try {
SystemInstance systemInstance = context.getSystemInstance();
if (null != systemInstance) {
field =
systemInstance.getClass().getDeclaredField(REFLECTION_FIELD_COMPONENTS);
field.setAccessible(true);
field.set(systemInstance, null);
}
} catch (final Throwable exception) {
this.logger.error(LOG_ERROR_TEAR_DOWN, exception);
}
/*
* Another greedy hog
*/
WebBeansContext webBeansContext = context.getWebBeansContext();
if (null != webBeansContext) {
try {
field =
webBeansContext.getClass().getDeclaredField(REFLECTION_FIELD_NOTIFICATIONMANAGER);
field.setAccessible(true);
field.set(webBeansContext, null);
} catch (final Throwable exception) {
this.logger.error(LOG_ERROR_TEAR_DOWN, exception);
}
try {
field =
webBeansContext.getClass().getDeclaredField(REFLECTION_FIELD_INTERCEPTORDECORATORPROXYFACTORY);
field.setAccessible(true);
field.set(webBeansContext, null);
} catch (final Throwable exception) {
this.logger.error(LOG_ERROR_TEAR_DOWN, exception);
}
}
} catch (final Throwable exception) {
this.logger.error(LOG_ERROR_TEAR_DOWN, exception);
}
}
{code}
> ApplicationComposers do not clear GC references on release
> ----------------------------------------------------------
>
> Key: TOMEE-4192
> URL: https://issues.apache.org/jira/browse/TOMEE-4192
> Project: TomEE
> Issue Type: Wish
> Reporter: Georg Tsakumagos
> Priority: Major
>
> The ApplicationComposers do not clear all references on release which could
> result in very high memory consumption for tests if injected classes a heavy
> weight. Having an project with many tests amplifies this problem enormous. An
> analysis of heap dumps shows different implementations holding references.
> {code:java|title=Example fat bean}
> @ApplicationScoped
> public class FatBean {
> private static final long serialVersionUID = -5814319377355637770L;
> private String payload;
>
> public FatBean() {
> super();
> /*
> * Big Memory Payload
> */
> char[] array = new char[1024 * 1024 * 128];
> Arrays.fill(array, '@');
> this.payload = new String(array);
> this.logger.info("Init FatProject Bean.");
> }
> }
> {code}
> Top overcome this bad behaviuour i've written an junit-extension to tear down
> all references by reflection. I like to get rid of this hack.
> {code:java|title=Teardown code}
> /**
> * Workaround for memory hogs in <em>OpenEJB</em>. Several components hold
> * references via {@link ThreadLocal} {@link List} and other instances.
> They are
> * not cleared on shutdown and prevent the <em>GC</em> from cleanup.
> *
> * @param composer The Composer to dispose.
> * @param testContext The TestContext.
> */
> private void tearDown(ApplicationComposers composer, ExtensionContext
> testContext) {
> this.logger.info(LOG_INFO_DESTROY,
> testContext.getTestInstanceLifecycle().orElse(null), composer);
> try {
> /*
> * Reflection magic
> */
> Field field =
> composer.getClass().getDeclaredField(REFLECTION_FIELD_APPCONTEXT);
> field.setAccessible(true);
> AppContext context = (AppContext) field.get(composer);
> /*
> * Clear Lists.
> */
> context.getWebContexts().clear();
> context.getInjections().clear();
> /*
> * Another greedy hog
> */
> try {
> SystemInstance systemInstance = context.getSystemInstance();
> if (null != systemInstance) {
> field =
> systemInstance.getClass().getDeclaredField(REFLECTION_FIELD_COMPONENTS);
> field.setAccessible(true);
> field.set(systemInstance, null);
> }
> } catch (final Throwable exception) {
> this.logger.error(LOG_ERROR_TEAR_DOWN, exception);
> }
> /*
> * Another greedy hog
> */
> WebBeansContext webBeansContext = context.getWebBeansContext();
> if (null != webBeansContext) {
> try {
> field =
> webBeansContext.getClass().getDeclaredField(REFLECTION_FIELD_NOTIFICATIONMANAGER);
> field.setAccessible(true);
> field.set(webBeansContext, null);
> } catch (final Throwable exception) {
> this.logger.error(LOG_ERROR_TEAR_DOWN, exception);
> }
> try {
> field =
> webBeansContext.getClass().getDeclaredField(REFLECTION_FIELD_INTERCEPTORDECORATORPROXYFACTORY);
> field.setAccessible(true);
> field.set(webBeansContext, null);
> } catch (final Throwable exception) {
> this.logger.error(LOG_ERROR_TEAR_DOWN, exception);
> }
> }
> } catch (final Throwable exception) {
> this.logger.error(LOG_ERROR_TEAR_DOWN, exception);
> }
> }
> {code}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)