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 行

非常感谢山姆

4

2 回答 2

3

如果您的后台线程没有足够快地写入磁盘,LinkedBlockingQueue(您未指定其容量)将增长直到它包含Integer.MAX_VALUE字符串。这对于您的 java 堆大小来说太大了。

指定容量,以便在队列满的情况下,调用 log 方法的线程将等待,同时将排队日志的某些部分转储到磁盘上:

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

在 log 方法中使用put而不是,add以便日志记录操作等待而不是抛出异常。

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

于 2012-06-26T10:55:18.447 回答
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();} 
} 
于 2012-06-26T10:55:21.087 回答