Maison  >  Questions et réponses  >  le corps du texte

java - Tomcat的Spring-MVC项目在重启一段时间后变卡

最近更新了程序之后,发现网页在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 {
                /**
                 * 更新全部灯具状态
                 */
                List<ManagementStation> mlist = 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 Status<OperationReturnMsgInfo> GetReturnedInfo(int frame_no) throws Exception{
        FrameController.addFrameToSendingQueue(frame_no);
        Status<OperationReturnMsgInfo> status=new Status<OperationReturnMsgInfo>();
        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<byte[]> return_frames = FrameController.GetReturnedFrame(frame_no);

        List<OperationReturnMsgInfo> olist= new ArrayList<OperationReturnMsgInfo>();
        if(return_frames !=null){
            for(byte[] return_frame:return_frames){
                List<OperationReturnMsgInfo> 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;
    }
ringa_leeringa_lee2743 Il y a quelques jours730

répondre à tous(2)je répondrai

  • 迷茫

    迷茫2017-04-18 10:55:08

    Le sujet peut trouver des outils d'analyse pour capturer en premier quelques informations utiles.
    BloquéLa raison la plus probable de la lenteur de l'exécution du programme est la préemption des ressourcescpu.

    Tout d'abord, l'affiche peut utiliser jstack pid pour imprimer la pile de threads et analyser le fonctionnement principal du thread, sur quelle ligne de code le programme s'exécute et quels calculs sont effectués ? Je vais vérifier les problèmes de code correspondants un par un

    Si jstack ne suffit pas, l'hôte peut également utiliser des outils tels que xrebel/yourkit pour aider au positionnement

    répondre
    0
  • 巴扎黑

    巴扎黑2017-04-18 10:55:08

    En regardant la description dans le titre, cela devrait être dû à une récupération de ressources provoquée par des fuites de mémoire.
    La recherche de fuites de mémoire ne peut pas être résolue en une seule réponse. Elle doit être combinée avec une analyse de code et de situation spécifique. Voici des idées de dépannage à titre de référence :

    1. Configurer Tomcat pour fuir et exporter des fichiers de tas
      Pour plus de détails, veuillez vous référer à la façon de configurer Tomcat pour générer un tas

    2. Utilisez des outils pour analyser les fichiers de headdump et localiser les informations anormales sur la pile
      Les outils d'analyse générale incluent IBM HeapAnalyzer, jhat et jmap. Vous pouvez vous référer à l'utilisation du dump JMAP et à l'analyse des fichiers de dump

    3. .
    4. Analyser s'il existe des exceptions dans la création et la destruction de la pile d'exceptions dans le code. Si elle n'est pas détruite normalement, cela peut entraîner des fuites

    5. .

    Il est recommandé à l'affiche d'essayer de maîtriser la méthode pour résoudre le problème, afin qu'il puisse contourner l'analogie lorsqu'il rencontrera de tels problèmes à l'avenir

    répondre
    0
  • Annulerrépondre