Java 弹簧&x2B;JPA PermGen内存不足

Java 弹簧&x2B;JPA PermGen内存不足,java,spring,hibernate,spring-mvc,jpa,Java,Spring,Hibernate,Spring Mvc,Jpa,EDIT1:28/05/2014 我尝试更改驱动程序(mysql-connector-java-5.1.30-bin和ojdbc7) 在这两种情况下,内存都会泄漏。例如(使用Java VisualVM)使用ojdbc并查看最近的GC,我看到: oracle.djbc.driver.ClockSource$ThreadCachingBlockSource$BlockReleaser不是contextClassLoader的“免费” 使用Mysql我也有同样的问题(使用sql驱动程序) 原创帖子:

EDIT1:28/05/2014

我尝试更改驱动程序(mysql-connector-java-5.1.30-bin和ojdbc7)

在这两种情况下,内存都会泄漏。例如(使用Java VisualVM)使用ojdbc并查看最近的GC,我看到:

oracle.djbc.driver.ClockSource$ThreadCachingBlockSource$BlockReleaser不是contextClassLoader的“免费”

使用Mysql我也有同样的问题(使用sql驱动程序)

原创帖子: 简单地配置spring和jpa,重启应用程序3/4次后,我的PermGen内存不足。使用Java VisualVM,我看到每次重启我都会有一个以上的类加载器(开始时我有4个类加载器,重启后我有5个类加载器,以此类推)。在我的WEB-INB中,我有任何库。我设置的唯一类是this(任何jsp和我执行逻辑的任何类,仅设置spring+jpa)

Im使用Tomcat8+Java 7 SDK:

引导配置

@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("/");
}
}
@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();
    }
}
@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;
}
}
Servlet配置

@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("/");
}
}
@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();
    }
}
@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;
}
}
@配置
@EnableWebMvc
@组件扫描(
basePackages=“it.dirimo.site”,
useDefaultFilters=false,
includeFilters=@ComponentScan.Filter(WebController.class)
)
公共类WebServletContextConfiguration扩展了WebMVCConfigureAdapter
{
@注入ApplicationContext ApplicationContext;
@注入ObjectMapper ObjectMapper;
@注入马歇尔勒;
@注入解组器解组器;
@注入SpringValidator适配器验证程序;
@凌驾
公共无效配置MessageConverters(

列表这是Tomcat/Spring/Hibernate的一个常见问题,通常没有适用于所有场景的明确答案。最有可能的是,在每次重新部署时都会创建动态类,存储在permgen中,并且类定义从来不会被垃圾收集。这通常不是di这实际上是Spring/Hibernate的一个bug,而是CGLIB和/或Tomcat的类加载器处理的“特性”

一些常见的建议:

  • -XX:+cmsclasssunloadingerabled-XX:+cmsclasssweapingenabled
    添加到tomcat启动选项中

  • 如果这是问题的原因,请远离CGLIB。CGLIB仅用于某些代理类型

  • 将JDBCJAR文件放在{tomcat}/lib中,而不是WEB-INF/lib中

互联网上还有很多其他的想法和方法,但一般来说,如果你无法解决上述问题,那么唯一的办法就是增加你的permgen,并计划每隔这么多次重新部署就重新启动tomcat


有趣的是(根据我自己的经验),这个问题在最新的library/server/jdk版本中并不是什么问题。

听起来可能是Tomcat 8中的一个bug。我已经在Tomcat 7上发布了它,并删除了@EnableLoadTimeWeaving。启动后(没有安装任何其他应用程序).Perm-Gen大约是37 MB。看了之后,我只需重新加载应用程序,Perm-Gen转到54.63。在第三次重新加载时,Perm-Gen的容量为72 MB(如前所述,应用程序完全为空,没有页面或服务)。使用Java VisualVM,如果我在未启动的实例上“显示最近的GC”,我会看到:classLoader->assertionLock(循环到此..任何一种方法都不能解决问题:(但好吧,我想我经常会重新启动应用程序服务器。但是,还有另一个问题。每次我调用一个执行数据库查询的方法时,PermGen都会增加,而不会减少。对于每个请求(DB connection->search)我有一个增加,从来没有减少…这是正常的..?在Tomcat 8+Java 8上部署它并使用最新的库(使用Tomcat/lib中的CMSClassUnloadingEnabled和mysql/ojdbc驱动程序)并不能解决问题。