在spring mvc app中找到内存泄漏

时间:2013-11-27 19:51:13

标签: java eclipse spring hibernate memory-leaks

我最近做了this tutorial并且代码运行正常。然后,今天,我在eclipse中重新打开了项目并选择了Run As ... Run on Server。应用程序似乎从eclipse控制台中运行的日志中经历了正常的加载过程,但是当我希望应用程序在浏览器中加载时,在eclipse控制台中出现以下错误消息:

Exception in thread "http-bio-8080-exec-3" java.lang.OutOfMemoryError: PermGen space  

我之前也运行了来自this tutorial的代码,并打开了一些blob文件,但我不认为这会导致问题,因为即使我关闭所有内容并重新启动计算机,此错误仍然存​​在在执行运行之前...再次在服务器上运行以下代码。

我用Google搜索错误和read postings关于内存泄漏的事情,例如将大量文件完全加载到内存中而不是使用输入流等。但是当我分析应用程序中的所有代码时,我找不到任何大变量。我发布下面的代码。如果我还有其他任何内容可以帮助您找到问题,请告诉我。

有人能告诉我内存泄漏的位置吗?

这是Link Controller:

@Controller
public class LinkController {

    @RequestMapping(value="/")
    public ModelAndView mainPage() {return new ModelAndView("home");}

    @RequestMapping(value="/index")
    public ModelAndView indexPage() {return new ModelAndView("home");}

}

这是团队控制员:

@Controller
@RequestMapping(value="/team")
public class TeamController {

    @Autowired
    private TeamService teamService;

    @RequestMapping(value="/add", method=RequestMethod.GET)
    public ModelAndView addTeamPage() {
            ModelAndView modelAndView = new ModelAndView("add-team-form");
            modelAndView.addObject("team", new Team());
            return modelAndView;
    }

    @RequestMapping(value="/add", method=RequestMethod.POST)
    public ModelAndView addingTeam(@ModelAttribute Team team) {
            ModelAndView modelAndView = new ModelAndView("home");
            teamService.addTeam(team);
            String message = "Team was successfully added.";
            modelAndView.addObject("message", message);
            return modelAndView;
    }

    @RequestMapping(value="/list")
    public ModelAndView listOfTeams() {
            ModelAndView modelAndView = new ModelAndView("list-of-teams");
            List<Team> teams = teamService.getTeams();
            modelAndView.addObject("teams", teams);
            return modelAndView;
    }

    @RequestMapping(value="/edit/{id}", method=RequestMethod.GET)
    public ModelAndView editTeamPage(@PathVariable Integer id) {
            ModelAndView modelAndView = new ModelAndView("edit-team-form");
            Team team = teamService.getTeam(id);
            modelAndView.addObject("team",team);
            return modelAndView;
    }

    @RequestMapping(value="/edit/{id}", method=RequestMethod.POST)
    public ModelAndView edditingTeam(@ModelAttribute Team team, @PathVariable Integer id) {
            ModelAndView modelAndView = new ModelAndView("home");       
            teamService.updateTeam(team);
            String message = "Team was successfully edited.";
            modelAndView.addObject("message", message);
            return modelAndView;
    }

    @RequestMapping(value="/delete/{id}", method=RequestMethod.GET)
    public ModelAndView deleteTeam(@PathVariable Integer id) {
            ModelAndView modelAndView = new ModelAndView("home");
            teamService.deleteTeam(id);
            String message = "Team was successfully deleted.";
            modelAndView.addObject("message", message);
            return modelAndView;
    }
}

这是TeamDAOImpl:

@Repository
public class TeamDAOImpl implements TeamDAO {
    @Autowired
    private SessionFactory sessionFactory;

    private Session getCurrentSession() {return sessionFactory.getCurrentSession();}

    public void addTeam(Team team) {getCurrentSession().save(team);}

    public void updateTeam(Team team) {
            Team teamToUpdate = getTeam(team.getId());
            teamToUpdate.setName(team.getName());
            teamToUpdate.setRating(team.getRating());
            getCurrentSession().update(teamToUpdate);
    }

    public Team getTeam(int id) {
            Team team = (Team) getCurrentSession().get(Team.class, id);
            return team;
    }

    public void deleteTeam(int id) {
            Team team = getTeam(id);
            if (team != null){getCurrentSession().delete(team);}
    }

    @SuppressWarnings("unchecked")
    public List<Team> getTeams() {
            return getCurrentSession().createQuery("from Team").list();
    }

}

这是Initializer:

public class Initializer implements WebApplicationInitializer {
    public void onStartup(ServletContext servletContext)throws ServletException {
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            ctx.register(WebAppConfig.class);
            servletContext.addListener(new ContextLoaderListener(ctx));
            ctx.setServletContext(servletContext);
            Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
            servlet.addMapping("/");
            servlet.setLoadOnStartup(1);
    }
}  

这是WebAppConfig:

@Configuration
@ComponentScan("com.sprhib")
@EnableWebMvc
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
public class WebAppConfig {
    private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
    private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
    private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
    private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
    private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
    private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
    private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";

    @Resource
    private Environment env;

    @Bean
    public DataSource dataSource() {
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
            dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
            dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
            dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
            return dataSource;
    }

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
            LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
            sessionFactoryBean.setDataSource(dataSource());
            sessionFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
            sessionFactoryBean.setHibernateProperties(hibProperties());
            return sessionFactoryBean;
    }

    private Properties hibProperties() {
            Properties properties = new Properties();
            properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
            properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
            return properties;        
    }

    @Bean
    public HibernateTransactionManager transactionManager() {
            HibernateTransactionManager transactionManager = new HibernateTransactionManager();
            transactionManager.setSessionFactory(sessionFactory().getObject());
            return transactionManager;
    }

    @Bean
    public UrlBasedViewResolver setupViewResolver() {
            UrlBasedViewResolver resolver = new UrlBasedViewResolver();
            resolver.setPrefix("/WEB-INF/pages/");
            resolver.setSuffix(".jsp");
            resolver.setViewClass(JstlView.class);
            return resolver;
    }
}  

这是团队:

@Entity
@Table(name="teams")
public class Team {
    @Id
    @GeneratedValue
    private Integer id;
    private String name;
    private Integer rating;
    public Integer getId() {return id;}
    public void setId(Integer id) {this.id = id;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public Integer getRating() {return rating;}
    public void setRating(Integer rating) {this.rating = rating;}
}  

这是TeamServiceImpl:

@Service
@Transactional
public class TeamServiceImpl implements TeamService {
    @Autowired
    private TeamDAO teamDAO;

    public void addTeam(Team team) {teamDAO.addTeam(team);}

    public void updateTeam(Team team) {teamDAO.updateTeam(team);}

    public Team getTeam(int id) {return teamDAO.getTeam(id);}

    public void deleteTeam(int id) {teamDAO.deleteTeam(id);}

    public List<Team> getTeams() {return teamDAO.getTeams();}

}  

编辑:

如果我应该设置JAVA_OPTS变量以允许类卸载,并增加内存大小,我如何在运行tomcat 7的Windows 7中这样做?

我的感觉是我需要创建一个Windows系统变量,然后可能在命令行上运行一些东西。但是什么?以下是我的开始:

JAVA_OPTS="-XX:MaxPermSize=128M -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled -Xms256m -Xmx512m"

2 个答案:

答案 0 :(得分:5)

如果要在Windows上更改tomcat实例的JAVA_OPTS,则需要通常在catalina.bat中编辑文件TOMCAT_BASE/bin/catalina.bat

但是,我会调整你指定的选项。首先,如果您指定-XX:+CMSClassUnloadingEnabled,则不需要-XX:+CMSPermGenSweepingEnabled

其次,要使-XX:+CMSClassUnloadingEnabled产生任何效果,您还必须指定-XX:+UseConcMarkSweepGC

因此,总而言之,编辑TOMCAT_BASE/bin/catalina.bat并在脚本开头的大rem语句块下(第99行的某处),添加以下行:

set JAVA_OPTS=-XX:MaxPermSize=128M -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -Xms256m -Xmx512m

请记住,如果您需要更多的PermGen空间,请将MaxPermSize增加到更高的值,但不使用垃圾收集选项(UseConcMarkSweepGCCMSClassUnloadingEnabled),您只需延长不可避免的java.lang.OutOfMemoryError: PermGen space

希望有所帮助

答案 1 :(得分:0)

您的应用程序实际上可能没有内存泄漏。当您多次重新部署应用程序时,服务器出现问题,最终会导致内存不足问题。不幸的是,此时你所能做的就是重启所有内容,你的应用程序运行正常。

看一下this question,它可以帮助你增加Java的可用内存,这样你就可以在遇到这个问题之前工作更长时间。

This questionthis answer也可能会有所帮助。