我为我的程序编写了一个后台日志记录线程,如果一个类需要一个记录器,它会从我的线程池中提取它,所以对于每个文件名,只有一个日志在运行。该类添加了需要通过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个行
非常感谢 萨姆
答案 0 :(得分:3)
如果您的后台线程没有足够快地写入磁盘,LinkedBlockingQueue(您未指定其容量)将会增长,直到它包含Integer.MAX_VALUE
个字符串。这对你的java堆大小来说太过分了。
指定容量,以便在完整队列的情况下,调用log方法的线程将等待排队日志的某些部分被转储到磁盘上:
private BlockingQueue<String> pq = new LinkedBlockingQueue<String>(1000);
在日志方法中使用put而不是add
,以便日志记录操作等待而不是抛出异常。
(您是否注意到您在写入磁盘时写的时间而不是记录时间?)
答案 1 :(得分: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();}
}