EDIT1: 28/05/2014
I've tried to change the driver (mysql-connector-java-5.1.30-bin AND ojdbc7).
In both cases the memory leak in on it. For example (using Java VisualVM) using ojdbc and looking at the nearest GC i see:
oracle.djbc.driver.ClockSource$ThreadCachingBlockSource$BlockReleaser isnt "free" from contextClassLoader
Using Mysql i have the same issue (with sql driver)
ORIGINAL POST: Simply configuring spring and jpa, after restart application 3/4 times i have PermGen Out of Memory. Using Java VisualVM i see that every restart i have one more class loader (at the beginning i have 4 class loader, after restart i have 5 and so on). In my WEB-INB i have any lib. The only classes i've setup are this (any jsp and any class where i do logic, setup only spring + jpa).
Im using Tomcat8 + Java 7 SDK:
Bootstrap configuration
@SuppressWarnings("unused")
@Order(1)
public class FrameworkBootstrap implements WebApplicationInitializer
{
@Override
public void onStartup(ServletContext container)
throws ServletException
{
container.getServletRegistration("default").addMapping("/resource/*");
AnnotationConfigWebApplicationContext rootContext =
new AnnotationConfigWebApplicationContext();
rootContext.register(RootContextConfiguration.class);
container.addListener(new ContextLoaderListener(rootContext));
AnnotationConfigWebApplicationContext webContext =
new AnnotationConfigWebApplicationContext();
webContext.register(WebServletContextConfiguration.class);
ServletRegistration.Dynamic dispatcher = container.addServlet(
"springWebDispatcher", new DispatcherServlet(webContext)
);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
Servlet configuration
@Configuration
@EnableWebMvc
@ComponentScan(
basePackages = "it.dirimo.site",
useDefaultFilters = false,
includeFilters = @ComponentScan.Filter(WebController.class)
)
public class WebServletContextConfiguration extends WebMvcConfigurerAdapter
{
@Inject ApplicationContext applicationContext;
@Inject ObjectMapper objectMapper;
@Inject Marshaller marshaller;
@Inject Unmarshaller unmarshaller;
@Inject SpringValidatorAdapter validator;
@Override
public void configureMessageConverters(
List<HttpMessageConverter<?>> converters
) {
converters.add(new ByteArrayHttpMessageConverter());
converters.add(new StringHttpMessageConverter());
converters.add(new FormHttpMessageConverter());
converters.add(new SourceHttpMessageConverter<>());
MarshallingHttpMessageConverter xmlConverter =
new MarshallingHttpMessageConverter();
xmlConverter.setSupportedMediaTypes(Arrays.asList(
new MediaType("application", "xml"),
new MediaType("text", "xml"),
new MediaType("text", "json")
));
xmlConverter.setMarshaller(this.marshaller);
xmlConverter.setUnmarshaller(this.unmarshaller);
converters.add(xmlConverter);
MappingJackson2HttpMessageConverter jsonConverter =
new MappingJackson2HttpMessageConverter();
jsonConverter.setSupportedMediaTypes(Arrays.asList(
new MediaType("application", "json"),
new MediaType("text", "json")
));
jsonConverter.setObjectMapper(this.objectMapper);
converters.add(jsonConverter);
}
@Override
public void configureContentNegotiation(
ContentNegotiationConfigurer configurer)
{
configurer.favorPathExtension(true).favorParameter(false)
.parameterName("mediaType").ignoreAcceptHeader(false)
.useJaf(false).defaultContentType(MediaType.APPLICATION_XML)
.mediaType("xml", MediaType.APPLICATION_XML)
.mediaType("json", MediaType.APPLICATION_JSON);
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers)
{
Sort defaultSort = new Sort(new Sort.Order(Sort.Direction.ASC, "id"));
Pageable defaultPageable = new PageRequest(0, 10, defaultSort);
SortHandlerMethodArgumentResolver sortResolver =
new SortHandlerMethodArgumentResolver();
sortResolver.setSortParameter("paging.sort");
sortResolver.setFallbackSort(defaultSort);
PageableHandlerMethodArgumentResolver pageableResolver =
new PageableHandlerMethodArgumentResolver(sortResolver);
pageableResolver.setMaxPageSize(100);
pageableResolver.setOneIndexedParameters(true);
pageableResolver.setPrefix("paging.");
pageableResolver.setFallbackPageable(defaultPageable);
resolvers.add(sortResolver);
resolvers.add(pageableResolver);
}
@Override
public void addFormatters(FormatterRegistry registry)
{
if(!(registry instanceof FormattingConversionService))
{
return;
}
DomainClassConverter<FormattingConversionService> converter =
new DomainClassConverter<>((FormattingConversionService)registry);
converter.setApplicationContext(this.applicationContext);
}
@Override
public Validator getValidator()
{
return this.validator;
}
@Override
public void addInterceptors(InterceptorRegistry registry)
{
super.addInterceptors(registry);
registry.addInterceptor(new LocaleChangeInterceptor());
}
@Bean
public LocaleResolver localeResolver()
{
return new SessionLocaleResolver();
}
@Bean
public ViewResolver viewResolver()
{
InternalResourceViewResolver resolver =
new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
resolver.setPrefix("/WEB-INF/jsp/view/");
resolver.setSuffix(".jsp");
return resolver;
}
@Bean
public RequestToViewNameTranslator viewNameTranslator()
{
return new DefaultRequestToViewNameTranslator();
}
}
Root configuration
@Configuration
@EnableScheduling
@EnableLoadTimeWeaving
@EnableAsync(
mode = AdviceMode.PROXY, proxyTargetClass = true,
order = 1
)
@EnableTransactionManagement(
mode = AdviceMode.PROXY, proxyTargetClass = true,
order = 2
)
@EnableJpaRepositories(
basePackages = "it.dirimo.site.repositories",
entityManagerFactoryRef = "entityManagerFactoryBean",
transactionManagerRef = "jpaTransactionManager"
)
@ComponentScan(
basePackages = "it.dirimo.site",
excludeFilters =
@ComponentScan.Filter({Controller.class, ControllerAdvice.class})
)
public class RootContextConfiguration implements AsyncConfigurer, SchedulingConfigurer
{
//private static final Logger log = LogManager.getLogger();
@Inject LoadTimeWeaver loadTimeWeaver;
@Bean
public MessageSource messageSource()
{
ReloadableResourceBundleMessageSource messageSource =
new ReloadableResourceBundleMessageSource();
messageSource.setCacheSeconds(-1);
messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());
messageSource.setBasenames(
"/WEB-INF/i18n/titles", "/WEB-INF/i18n/messages",
"/WEB-INF/i18n/errors", "/WEB-INF/i18n/validation"
);
return messageSource;
}
@Bean
public LocalValidatorFactoryBean localValidatorFactoryBean()
{
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(this.messageSource());
return validator;
}
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor()
{
MethodValidationPostProcessor processor =
new MethodValidationPostProcessor();
processor.setValidator(this.localValidatorFactoryBean());
return processor;
}
@Bean
public ObjectMapper objectMapper()
{
ObjectMapper mapper = new ObjectMapper();
mapper.findAndRegisterModules();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE,
false);
return mapper;
}
@Bean
public Jaxb2Marshaller jaxb2Marshaller()
{
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setPackagesToScan(new String[] { "it.dirimo.site" });
return marshaller;
}
@Bean
public DataSource fileSearchDataSource()
{
JndiDataSourceLookup lookup = new JndiDataSourceLookup();
return lookup.getDataSource("jdbc/DIR");
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean()
{
Map<String, Object> properties = new Hashtable<>();
properties.put("javax.persistence.schema-generation.database.action",
"none");
properties.put("hibernate.ejb.use_class_enhancer", "true");
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setDatabasePlatform("org.hibernate.dialect.Oracle10gDialect");
LocalContainerEntityManagerFactoryBean factory =
new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(adapter);
factory.setDataSource(this.fileSearchDataSource());
factory.setPackagesToScan("it.dirimo.site.entities");
factory.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
factory.setValidationMode(ValidationMode.NONE);
factory.setLoadTimeWeaver(this.loadTimeWeaver);
factory.setJpaPropertyMap(properties);
return factory;
}
@Bean
public PlatformTransactionManager jpaTransactionManager()
{
return new JpaTransactionManager(
this.entityManagerFactoryBean().getObject()
);
}
@Bean
public ThreadPoolTaskScheduler taskScheduler()
{
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(20);
scheduler.setThreadNamePrefix("task-");
scheduler.setAwaitTerminationSeconds(60);
scheduler.setWaitForTasksToCompleteOnShutdown(true);
return scheduler;
}
@Override
public void configureTasks(ScheduledTaskRegistrar registrar) {
TaskScheduler scheduler = this.taskScheduler();
registrar.setTaskScheduler(scheduler);
}
@Override
public Executor getAsyncExecutor() {
Executor executor = this.taskScheduler();
return executor;
}
}