java - 在 Spring MVC 应用程序中查找内存泄漏

标签 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 文件,但我不认为这是导致问题的原因,因为即使我关闭所有内容并在执行运行方式之前重新启动计算机时此错误仍然存​​在...再次在服务器上运行下面的代码。

我搜索了错误和read posts关于内存泄漏,例如将大量文件完全加载到内存而不是使用输入流等。但是当我分析应用程序中的所有代码时,我找不到任何大变量。我在下面发布代码。

如何找到内存泄漏?

这是链接 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 :

@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();
    }

}

这是初始化程序:

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"

最佳答案

如果你想在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 语句 block 下(第 99 行附近的某处) ish), 添加这一行:

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

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

希望对你有帮助

关于java - 在 Spring MVC 应用程序中查找内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20251800/

相关文章:

java - 将 TableRow 与 TextView 放在一起

java - 我想知道如何在eclipse中的java项目上使用延迟来使用绘图组件

android - 为什么 Android xml 布局文件无法通过 ctrl+space 识别内容辅助?

java - 在单元测试中使用 SpringRunner 可以吗?

java - 如何将消费者组与 Spring Data Redis for Redis Streams 一起使用(继续获取 NOGROUP)?

java - Spring MVC 在使用 Ajax 调用时返回简单文本而不是 JSON

java - 来自枚举的无限流

Java 三元运算符优先级?给出不同的输出

Java - JSP/Servlet 示例中的 NullPointerException?

java - 通过java程序读取大型输入文件(10gb)