登录线程内存泄漏(Log thread memory leak)

2019-09-18 13:24发布

我已经编写后台记录线程我的程序,如果一个类需要它拉它从我的线程池一个记录器,所以对于每个文件名,只有一个日志运行。 类,添加了什么这需要通过日志(字符串)被记录。

不管怎样,每当我经过一段时间设定登录并运行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的

非常感谢山姆

Answer 1:

如果你的后台线程不会写入到磁盘速度不够快,对的LinkedBlockingQueue (其容量你不指定)将增长,直到它包含Integer.MAX_VALUE字符串。 这是太多的Java堆大小。

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

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

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

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



Answer 2:

我相信,有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();} 
} 


文章来源: Log thread memory leak