2012-06-26 88 views
1

我为我的程序编写了一个后台日志记录线程,如果一个类需要一个记录器,它将它从我的线程池中拉出来,所以对于每个文件名,只有一个日志正在运行。该类添加了任何需要通过log(String)记录的内容。日志线程内存泄漏

无论如何,无论何时我设置日志记录并在一段时间后运行writetolog(),我会得到heapoutofmemory异常。这是由日志线程引起的,但我无法看到内存泄漏的位置,而且我在线程上并不是那么棒。我唯一的想法是,它是在缓冲作家?

import java.io.File; 
import java.io.IOException; 

import java.io.FileWriter; 
import java.util.Calendar; 
import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.LinkedBlockingQueue; 

public class Log extends Thread{ 
private String file; 
private BlockingQueue<String> pq = new LinkedBlockingQueue<String>(); 
private BufferedWriter bw; 
private boolean Writing; 

@Depreciated 
public Log(){ 
    super(); 
    file = "log.txt"; 

    start(); 
} 

public Log(ThreadGroup tg, String fileName){ 
    super(tg,fileName); 
    file = fileName; 
    try { 
     new File(file).createNewFile(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    start(); 
} 

public Log(String fileName){ 
    file = fileName; 
    try { 
     new File(file).createNewFile(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    start(); 
} 

@Override 
public void run(){ 
    //System.out.println("Log Thread booted " +file); 

    while(Run.running){ 
     if (!Writing){ 
      if(Run.logging) 
      writeToLog(); 
     } 
     try{ 
      Thread.sleep(500); 
     }catch(InterruptedException e){ 
      Thread.currentThread().interrupt(); 
      break; 
     } 


    } 
    //System.out.println("Log Thread shutting down " +file); 
} 

public synchronized void log(String s){ 
    if(Run.logging) 
    pq.add(s); 
} 

private void writeToLog(){ 
    try{ 
     Writing = true; 

     bw = new BufferedWriter(new FileWriter(file, true)); 
    while(!pq.isEmpty()){ 

      bw.write(Calendar.getInstance().getTime().toString() +" " +pq.poll()); 
      bw.newLine(); 

    } 

    bw.flush(); 
    bw.close(); 
    Writing = false; 
    }catch(Exception e){Writing = false; e.printStackTrace();} 
} 



} 

编辑 - 值得一提的还有,在程序的上下文中,记录100的 - 1000年线的

非常感谢 山姆

回答

3

如果你的后台线程不写到磁盘速度不够快,LinkedBlockingQueue(其容量未指定)将增长,直至包含Integer.MAX_VALUE字符串。这对于你的java堆大小来说太多了。

指定,这样,在全队列的情况下,线程调用日志方法将等待一个容量,而排队的日志的某些部分是在磁盘上倾倒:

private BlockingQueue<String> pq = new LinkedBlockingQueue<String>(1000); 

使用put,而不是add在日志方法,以便日志操作等待而不是引发异常。

(你有没有注意到你写的时间记录在磁盘上,而不是时间写?)

+0

是这部分解决了我的问题是溢出的问题,但是什么是正确的方法来允许然后在添加之前清除? –

+0

因为此刻我现在得到一个非法状态异常 - 队列已满 –

+1

并使用put代替add。 –

1

我相信有private BufferedWriter bw;的成员变量引起的麻烦。由于您只在writeToLog()函数中使用它,所以没有理由将它作为成员变量,并且每次都由多个线程实例化。在函数内创建BufferedWriter会在对象超出范围时立即GC。

private void writeToLog(){ 
    try{ 
     Writing = true; 

     BufferedWriter bw = new BufferedWriter(new FileWriter(file, true)); 
    while(!pq.isEmpty()){ 

      bw.write(Calendar.getInstance().getTime().toString() +" " +pq.poll()); 
      bw.newLine(); 

    } 

    bw.flush(); 
    bw.close(); 
    Writing = false; 
    }catch(Exception e){Writing = false; e.printStackTrace();} 
} 
+0

我刚刚尝试过这个,它仍然runoutofheap,虽然好主意,虽然 –