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

发布于 2021-11-24 04:19:27 字数 6331 浏览 843 评论 10

该程序是用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




请教各位大侠 哪里造成内存溢出了啊……?



如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

千纸鹤带着心事 2021-11-29 05:25:02

老实说我也不清楚,这个项目不是我做的。而且DAO层用的是hibernate,但是没有impl实现类。用了一套公司自己封装的DAO框架,只要写SQL语句,按照其他Service层和DAO接口类的方法定义规范来定义就可以了。 hibernate框架中关闭连接通常是怎么做的?我都不是很记得了…… 现在Service层和DAO层都是通过注解来配置成Spring的bean的。

回眸一笑 2021-11-29 04:43:52

我估计是连接的问题

海之角 2021-11-29 03:37:25

你怎么关闭连接的?

柳若烟 2021-11-29 03:27:02

你在job的执行方法里面去再一次初始化Spring容器。这样不对的,所有的Spring Bean的配置,一般只启动一个ApplicationContext

长安忆 2021-11-29 02:47:41

回复
嗯 昨晚在家我发现可能这里不对 今早回来,试了一下,果然是这里出问题了,创建了太多Spring的Bean实例,谢啦!

回忆凄美了谁 2021-11-29 02:38:16

引用来自“ForEleven”的评论

这样用Spring 不出问题才怪。不是代码的问题,是Spring+Hibernate根本不是这样用的,你应该在Quartz的一个Job里面注入一个DataSource,整个数据库连接交给Spring容器管理

好听的两个字的网名 2021-11-29 01:12:40

往Quartz里注入datasource,Quartz会默认去数据库里找一堆叫QRTZ_LOCKS的表

网名女生简单气质 2021-11-28 18:57:35

回复
是么?这个没注意过,一般是注入Service层的Bean。这里只是表示这个意思

屌丝范 2021-11-28 16:08:08

这样用Spring 不出问题才怪。不是代码的问题,是Spring+Hibernate根本不是这样用的,你应该在Quartz的一个Job里面注入一个DataSource,整个数据库连接交给Spring容器管理

醉生梦死 2021-11-27 18:42:00

结一下帖:

其实问题很简单,是低级错误啦……

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;
	}

我把定时器任务要使用的Service放在static代码块中获取了。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文