设为首页 加入收藏

TOP

Java应用线程泄漏原因分析与避免(一)
2017-03-30 14:17:53 】 浏览:465
Tags:Java 应用 线程 泄漏 原因分析 避免

起因-日志丢失


生产上出现过几次日志丢失的问题,我们日志每小时生成一个文件,然后每个小时刚到整点切换的时候会生成新文件然后正常输出日志,到了固定时点就空了,只有一个定时清理数据的线程打的几行日志。


通过分析,是因为我们的应用部署在weblogic上,每次重新发war包并不会重启weblogic,只是停止之前的应用,重新启动一个新的,而之前的应用有个别线程没能关闭,与新应用同时打日志,出现了问题。


泄漏的线程与新应用的线程各自持有一个log4j的appender,关键这两个appender的规则完全一致。



新应用的线程一直在打印日志,到了整点就切换,而泄漏的线程每半个小时才被唤醒一次,然后打印几句日志。


我们来看一下log4j切换日志的代码:


 /**
    Rollover the current file to a new file.
  */
  void rollOver() throws IOException {
 
    /* Compute filename, but only if datePattern is specified */
    if (datePattern == null) {
      errorHandler.error("Missing DatePattern option in rollOver().");
      return;
    }
 
    String datedFilename = fileName+sdf.format(now);
    // It is too early to roll over because we are still within the
    // bounds of the current interval. Rollover will occur once the
    // next interval is reached.
    if (scheduledFilename.equals(datedFilename)) {
      return;
    }
 
    // close current file, and rename it to datedFilename
    this.closeFile();
 
    //!!!!!!!!!!重点在这!!!!
    //如果存在已经重名的就给删掉。
    File target  = new File(scheduledFilename);
    if (target.exists()) {
      target.delete();
    }
 
    File file = new File(fileName);
    boolean result = file.renameTo(target);
    if(result) {
      LogLog.debug(fileName +" -> "+ scheduledFilename);
    } else {
      LogLog.error("Failed to rename ["+fileName+"] to ["+scheduledFilename+"].");
    }
 
    try {
      // This will also close the file. This is OK since multiple
      // close operations are safe.
      this.setFile(fileName, true, this.bufferedIO, this.bufferSize);
    }
    catch(IOException e) {
      errorHandler.error("setFile("+fileName+", true) call failed.");
    }
    scheduledFilename = datedFilename;
 
  }


假如现在刚到10点了,因为新应用一直在打印日志,10点时切换了一个新日志,然后不停的打日志,结果到了10:15,另一个appender也要打日志了,它发现过了10点了,自己原来持有的日志还是9点点,就切换一个,发现已经有重名点,就删掉重建了,这就是原因。可是有人会说前一个appender持有的文件句柄文件被删了,它不应该报异常吗?经过我的实验,没有任何异常反应。


public static void main(String[] args) throws IOException {
    File a = new File("test.txt");
    BufferedWriter bw1 = new BufferedWriter(
            new FileWriter(a));
    bw1.write("aaaaaaaa");
    bw1.flush();
    a.delete();
    bw1.write("aaaaaaaaa");
    bw1.flush();
   
    File b = new File("test.txt");
    BufferedWriter bw2 = new BufferedWriter(
            new FileWriter(b));
    bw2.write("bbbbbbbbb");
    bw2.flush();
   
    bw1.write("aaaaaaaaa");
    bw1.flush();
   
}


上面这段代码不会有任何异常,最终生成的文件内容是bbbbbbbbb。


这个问题只是线程泄漏带来的问题之一,还有与之对应的内存泄漏等其它问题。接下来就来分析一下线程泄漏等原因与如何避免此类问题。


应用服务器如何清理线

首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇对Spring Web启动时IOC源码研究 下一篇Java中volatile关键字的含义

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目