用Spring定时器写了个程序,查询数据库固定次数后,内存溢出-问答-阿里云开发者社区-阿里云

开发者社区> 问答> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

用Spring定时器写了个程序,查询数据库固定次数后,内存溢出

该程序是用Spring定时器执行的,定时用hibernate框架查询数据库,将查询到的结果写成文本文件。

启动定时器之后每次在生成了52个文本文件之后,就内存溢出了。

由于代码不多我直接贴代码和错误提示吧!

希望各位高手有时间帮忙看一下!

下面的是定时器执行的类和方法

public class BillInfoExporter {
    private static String[] LOCATIONS = { "spring-hibernate.xml", "spring-minidao.xml" };
    private Map<String, String> config;
     
    protected final static Logger logger = Logger.getLogger("log4j.properties");
     
    @SuppressWarnings("unused")
    public boolean billInfoExport() {
        ApplicationContext ctx = null;
        BillingService billingService = null;
        TextFileWriter textFileWriter = null;
        File file = null;
        List<Map> ioGoods = null;
        List<Map> selfGoods = null;
        try {
             
            if (ctx == null) {
                ctx = new ClassPathXmlApplicationContext(LOCATIONS);
                if (billingService == null) {
                    billingService = (BillingService) ctx.getBean("billingServiceImpl");
                }
            }
             
            StringBuffer buff = new StringBuffer();
             
             
            ioGoods = billingService.billingIOGoodsMessage();
            BillExporterUtils.billExport(buff, ioGoods);
             
            selfGoods = billingService.billingSelfGoodMessage();
            BillExporterUtils.billExport(buff, selfGoods);
 
            file = new File(buildFileName());
             
 
            textFileWriter = new TextFileWriter(file, false);
            textFileWriter.outPut(buff.toString());
             
            buff = null;
            return true;
        } catch (Exception e) {
            String resultLog = "未能成功从数据库中查询自用物资、备案清单进出单号信息,当前系统日期为:" + CalendarUtils.formatDate(new Date());
            logger.error(resultLog, e);
        } finally{
            try {
                if(textFileWriter!=null){
                    textFileWriter.closeFile();
                    textFileWriter = null;
                }
                if (ioGoods != null) {
                    ioGoods = null;
                }
                if (selfGoods != null) {
                    selfGoods = null;
                }
                System.gc();
            } catch (Exception e) {
                e.printStackTrace();
            }
             
        }
         
        return false;
    }
     
     
    private String buildFileName(){
        String fileName = null;
        StringBuffer sBuffer = new StringBuffer();
        Date currentDate = new Date();
         
        fileName = config.get("outputPath");
         
        if (StringUtils.isBlank(fileName)) {
            fileName = System.getProperty("user.dir") + "/output";
            System.out.println(fileName);
        }
         
        sBuffer.append(fileName).append("/");
         
        sBuffer.append("SB_");
         
        sBuffer.append(CalendarUtils.format(currentDate, "MM")).append('_');
         
        sBuffer.append(currentDate.getTime());
         
        sBuffer.append(".bi");
         
        fileName = sBuffer.toString();
         
        return fileName;
         
    }
 
    public Map<String, String> getConfig() {
        return config;
    }
 
    public void setConfig(Map<String, String> config) {
        this.config = config;
    }
 
}
下面是加载Spring定时器的主函数类

public class BillInfoScheduler {
     
    public static void main(String[] args) {
        try {
            String configFile = null;
            if(args!=null && args.length>0){
                configFile = args[0].trim();
            }else{
                configFile = "scheduler.xml";
            }
             
            execute(configFile);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
     
    public static void execute(String configFile){
        ApplicationContext ctx = new ClassPathXmlApplicationContext(configFile);
    }
     
}
下面是定时器的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <!-- 第零步: 配置计费信息输出的路径 -->
    <bean id="config" class="java.util.HashMap">
        <constructor-arg>
            <map>
                <entry key="outputPath" value="D:/work_dev/YanKe/Source/ECLink_packed/output" />
            </map>
        </constructor-arg>
    </bean>
 
    <!-- 第一步: 配置好要定时调用的业务类 -->
    <bean id="billInfoExporter" class="org.broadengate.eclink.schedule.BillInfoExporter">
        <property name="config" ref="config" />
    </bean>
 
    <!-- 第二步: 定义好具体要使用类的哪一个业务方法 -->
    <bean id="printTimerJob"
        class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <!-- 目标bean -->
        <property name="targetObject" ref="billInfoExporter" />
        <!-- 要执行目标bean的哪一个业务方法 -->
        <property name="targetMethod" value="billInfoExport" />
        <!-- 是否并发 -->
        <property name="concurrent" value="false" />
    </bean>
 
    <!-- 第三步: 定义好调用模式: 如每隔2秒钟调用一次或每天的哪个时间调用一次等 -->
    <bean id="printTimerTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <property name="jobDetail" ref="printTimerJob" />
        <property name="cronExpression" value="0/2 * * * * ?" />
        <!-- 每月最后一日的上午10:15触发 0 15 10 L * ? -->
        <!-- 每天晚上23:00触发 0 0 23 * * ? -->
    </bean>
 
    <!-- 启动定时器 -->
 
    <!--第四步 把定义好的任务放到调度(Scheduler)工厂里面,注意这里的ref bean -->
    <bean id="schedulerFactoryBean"
        class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="applicationContextSchedulerContextKey" value="applicationContext" />
        <property name="triggers">
            <list>
                <ref bean="printTimerTrigger" />
            </list>
        </property>
    </bean>
 
    <!-- end -->
</beans>


控制台报的错,是说我在执行定时任务的方法是时由于内存溢出而无法执行吗?

[org.quartz.core.JobRunShell]Job DEFAULT.printTimerJob threw an unhandled Exception:  
org.springframework.scheduling.quartz.JobMethodInvocationFailedException: Invocation of method 'billInfoExport' on target class [class org.broadengate.eclink.schedule.BillInfoExporter] failed; nested exception is java.lang.OutOfMemoryError: PermGen space
 at org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean$MethodInvokingJob.executeInternal(MethodInvokingJobDetailFactoryBean.java:320)
 at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:113)
 at org.quartz.core.JobRunShell.run(JobRunShell.java:216)
 at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)
Caused by: java.lang.OutOfMemoryError: PermGen space

展开
收起
a123456678 2016-03-17 11:15:31 4823 0
1 条回答
写回答
取消 提交回答
  • a123456678

    BillInfoExporter是定时器调用的类,billInfoExport()是定时器执行的方法。

    原先,我在billInfoExport()方法中创建Spring的ApplicationContext对象,并且通过它获得我要使用的Service类对象。

    这样一来,每次定时器调用该方法都去初始化Spring,创建很多Bean实例。于是就内存溢出了……

    修改后的代码:

    public class BillInfoExporter {
        private static String[] LOCATIONS = { "spring-hibernate.xml",
                "spring-minidao.xml" };
        private Map<String, String> config;
     
        protected final static Logger logger = Logger.getLogger("log4j.properties");
     
        private static ApplicationContext ctx = null;
     
        private static BillingService billingService = null;
         
        static{
            if (ctx == null) {
                ctx = new ClassPathXmlApplicationContext(LOCATIONS);
                if (billingService == null) {
                    billingService = (BillingService) ctx.getBean("billingServiceImpl");
                }
            }
        }
     
        @SuppressWarnings("unused")
        public boolean billInfoExport() {
            TextFileWriter textFileWriter = null;
            File file = null;
            List<Map> ioGoods = null;
            List<Map> selfGoods = null;
            try {
     
                StringBuffer buff = new StringBuffer();
     
                ioGoods = billingService.billingIOGoodsMessage();
                BillExporterUtils.billExport(buff, ioGoods);
     
                selfGoods = billingService.billingSelfGoodMessage();
                BillExporterUtils.billExport(buff, selfGoods);
     
                file = new File(buildFileName());
     
                textFileWriter = new TextFileWriter(file, false);
                textFileWriter.outPut(buff.toString());
     
                buff = null;
                return true;
            } catch (Exception e) {
                String resultLog = "未能成功从数据库中查询自用物资、备案清单进出单号信息,当前系统日期为:"
                        + CalendarUtils.formatDate(new Date());
                logger.error(resultLog, e);
            } finally {
                try {
                    if (textFileWriter != null) {
                        textFileWriter.closeFile();
                        textFileWriter = null;
                    }
                    if (ioGoods != null) {
                        ioGoods = null;
                    }
                    if (selfGoods != null) {
                        selfGoods = null;
                    }
                    System.gc();
                } catch (Exception e) {
                    e.printStackTrace();
                }
     
            }
     
            return false;
        }
    2019-07-17 19:04:54
    赞同 展开评论 打赏
问答排行榜
最热
最新
相关电子书
更多
电商网站需求分析和架构设计Spring Boot2.6入门
立即下载
云上Docker的Spring Cloud微服务应用实践分享
立即下载
Spring Boot 2.6.0电商网站开发实战
立即下载