最近更新了程序之后,发现网页在tomcat重启一阵子之后变得异常的卡。不知道为什么。发现了好多内存泄漏的警告,觉得是不是因为不正常的关闭导致内存不足呢,就试了几个方法。
最先试着把tomcat的context.xml里面设置缓存最大值,貌似设到了100000,启动后发现速度不错,但过了一段时间又卡得不得了了。
再之后把服务器的内存调大了,问题还是照样出现。而且每次系统的缓存只会越来越多,不会减少。
上网看了一些类似问题的回答,有人说是java获取数据库的效率不高而造成的,但是我觉得我这个问题应该不是出在这,因为有很多需要获取数据库的函数代码都变,以前就没有出现过这种问题,为什么现在变成这样呢?不过最近倒是有一些改动,例如添加了两个TimerTask。倒觉得应该问题不回出在这里吧。
package x.xx.xxx; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Timer; import java.util.TimerTask; import javax.annotation.Resource; import org.apache.log4j.Logger; import x.xx.xxx.ManagementStation; import x.xx.xxx.ManagementStationService; /** * 源代码来自《java定时任务,每天定时执行任务》 * http://www.cnblogs.com/cvst/articles/5818233.html * */ public class TimerManager { @Resource RemoteControlController remoteControlController; @Resource ManagementStationService managementStationService; @Resource ControllerStatusController controllerStatusController; // 时间间隔 private static final long PERIOD_DAY = 24 * 60 * 60 * 1000; private static final int START_TIME = 1; public void initTimerManager() { Calendar calendar = Calendar.getInstance(); /*** 定制每日1:00执行方法 ***/ calendar.set(Calendar.HOUR_OF_DAY, START_TIME); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); Date date = calendar.getTime(); // 第一次执行定时任务的时间 Date date2 = calendar.getTime(); // 如果第一次执行定时任务的时间 小于 当前的时间 // 此时要在第一次执行定时任务的时间加一天,以便此任务在下个时间点执行。如果不加一天,任务会立即执行。 if (date.before(new Date())) { date = this.addDay(date, 1); } Timer timer = new Timer(); Timer timer2 = new Timer(); UpdateDailyEletricPowerTimerTask task = new UpdateDailyEletricPowerTimerTask(); // 安排指定的任务在指定的时间开始进行重复的固定延迟执行。 timer.schedule(task, date, PERIOD_DAY); UpdateLampStatusTimerTask task2 = new UpdateLampStatusTimerTask(); timer2.schedule(task2, date2, PERIOD_DAY); } // 增加或减少天数 public Date addDay(Date date, int num) { Calendar startDT = Calendar.getInstance(); startDT.setTime(date); startDT.add(Calendar.DAY_OF_MONTH, num); return startDT.getTime(); } public class UpdateDailyEletricPowerTimerTask extends TimerTask { private Logger log = Logger.getLogger(UpdateLampStatusTimerTask.class); @Override public void run() { try { /** * 查询前昨两天日冻结正向有功总电量 */ Calendar now = Calendar.getInstance(); int year = now.get(Calendar.YEAR) - 2000; int month = now.get(Calendar.MONTH) + 1; int day = now.get(Calendar.DATE); remoteControlController.dailyPositiveElectricPowerCollecting(year, month, day); } catch (Exception e) { log.info("-------------NFDFlightDataTimerTask解析信息发生异常--------------"); } } } public class UpdateLampStatusTimerTask extends TimerTask { private Logger log = Logger.getLogger(UpdateLampStatusTimerTask.class); @Override public void run() { try { /** * 更新全部灯具状态 */ Listmlist = managementStationService.getManagementStationList(); StringBuffer temp=new StringBuffer(""); for(ManagementStation m:mlist) temp.append(m.getMid()+","); String[] arr = temp.toString().split(","); boolean realTime = false; controllerStatusController.UpdateControllerStatus(arr,realTime); } catch (Exception e) { log.info("-------------UpdateLampStatusTimerTask解析信息发生异常--------------"); } } }
不过系统变得死卡死卡的的时候其实是开启thread和进行socket通讯之后。
不过不知道问题出在前置机于客户端的通讯那,还是我这边的系统程序问题,下面是系统接收返回信息的线程,请各位大虾过目过目,谢谢。
private StatusGetReturnedInfo(int frame_no) throws Exception{ FrameController.addFrameToSendingQueue(frame_no); Status status=new Status (); long beginTime = System.currentTimeMillis(); boolean over_runtime = false; /** * 如果超过最大接收时间RUNTIME_MAX就直接把接收到的信息返回页面 * 其他的报文继续在后台进行接收 */ while(FrameController.getExpectReutrnedFrameAmount(frame_no) != 0){ Thread.sleep(1000); long nowTime = System.currentTimeMillis(); over_runtime = nowTime - beginTime > RUNTIME_MAX? true : false; if(over_runtime) break;//超时跳出 } List return_frames = FrameController.GetReturnedFrame(frame_no); List olist= new ArrayList (); if(return_frames !=null){ for(byte[] return_frame:return_frames){ List olisttmp = parseFrontEndMsg(return_frame); if(olisttmp != null) olist.addAll(olisttmp); } status.setCode(1); }else{ status.setCode(0); } status.setList(olist); if(!over_runtime){ FrameController.RecallFrameNo(frame_no); }else{ /** * 后台处理超时没有返回的报文 */ final int tmp_frame_no = frame_no; new Thread(new Runnable(){ @Override public void run() { int frame_no_in_the_thread = tmp_frame_no;//FIXME 有点问题:如果tmp_frame_no在运行到这行时被其他线程改变了,怎么办? long beginTime = System.currentTimeMillis(); boolean over_runtime = false; int lastExpectReutrnedFrameAmount = FrameController.getExpectReutrnedFrameAmount(frame_no_in_the_thread); while(FrameController.getExpectReutrnedFrameAmount(frame_no_in_the_thread) != 0){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } long nowTime = System.currentTimeMillis(); over_runtime = nowTime - beginTime > BG_RUNTIME_MAX? true : false; if(over_runtime) { //再超时便强制回收帧序号,虽然暂时和直接回收没有区别。 FrameController.CompulsivelyRecallFrameNo(frame_no_in_the_thread); return; } /** * 如果该帧返回报文有继续更新,重置beginTime * 主要用于十分花时间的多报文返回操作RUNTIME_MAX的话就直接返回到页面。 * 相当于如果下一个报文返回间隔的时间大于RUNTIME_MAX就强行关闭对该帧的返回报文的接收 */ if(lastExpectReutrnedFrameAmount != FrameController.getExpectReutrnedFrameAmount(frame_no_in_the_thread)){ lastExpectReutrnedFrameAmount = FrameController.getExpectReutrnedFrameAmount(frame_no_in_the_thread); beginTime = System.currentTimeMillis(); } FrameController.RecallFrameNo(frame_no_in_the_thread); } }).start(); } return status; }
看题注描述,应该是内存泄漏引起资源抢夺导致。
查找内存泄漏不是一篇回答可以解决,还要结合具体代码和情况分析,这里给出排查思路供参考:
配置Tomcat泄漏导出堆文件
具体参考如何配置tomcat产生heapdump
通过工具分析分析headdump文件,定位异常堆栈信息
常规分析工具有IBM HeapAnalyzer、jhat、jmap,可以参考使用JMAP dump及分析dump文件
分析代码中异常堆栈创建和销毁是否存在异常,如未正常销毁导致泄漏
建议楼主尝试掌握方法来解决问题,以后碰到此类问题就可以触类旁通了
题主可以找一些分析工具,先捕捉一些有用的信息。
变卡程序执行过慢最有可能的原因是抢占资源cpu
。
首先楼主可能使用
jstack pid
打印出线程堆栈,分析一下线程主要是在如何工作,程序运行到哪行代码,在做什么计算?在去逐一排查对应的代码问题如果
jstack
不够楼主还可以使用xrebel
/yourkit
这类工具辅助定位
亲,你的异常信息里面,那个url好像本来就访问不了吧,所以404了,就爬不到数据了呀