Java 日志线程内存泄漏
我已经为我的程序编写了一个后台日志线程,如果一个类需要一个记录器,它会从我的线程池中提取它,所以对于每个文件名,只有一个日志正在运行。类,添加任何需要通过日志(字符串)记录的内容 不管怎样,每当我设置登录并在一段时间后运行writetolog()时,我都会遇到HeapOutMemory异常。这是由日志线程造成的,但我看不出内存泄漏在哪里,我也不太擅长线程。我唯一的想法是它在缓冲写入程序中Java 日志线程内存泄漏,java,multithreading,memory-leaks,thread-safety,Java,Multithreading,Memory Leaks,Thread Safety,我已经为我的程序编写了一个后台日志线程,如果一个类需要一个记录器,它会从我的线程池中提取它,所以对于每个文件名,只有一个日志正在运行。类,添加任何需要通过日志(字符串)记录的内容 不管怎样,每当我设置登录并在一段时间后运行writetolog()时,我都会遇到HeapOutMemory异常。这是由日志线程造成的,但我看不出内存泄漏在哪里,我也不太擅长线程。我唯一的想法是它在缓冲写入程序中 import java.io.File; import java.io.IOException; impo
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();}
}
}
导入java.io.File;
导入java.io.IOException;
导入java.io.FileWriter;
导入java.util.Calendar;
导入java.util.concurrent.BlockingQueue;
导入java.util.concurrent.LinkedBlockingQueue;
公共类日志扩展线程{
私有字符串文件;
private BlockingQueue pq=新建LinkedBlockingQueue();
专用缓冲写入程序bw;
私有布尔书写;
@贬值
公共日志(){
超级();
file=“log.txt”;
start();
}
公共日志(线程组tg,字符串文件名){
super(tg,文件名);
文件=文件名;
试一试{
新建文件(File).createNewFile();
}捕获(IOE异常){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
start();
}
公共日志(字符串文件名){
文件=文件名;
试一试{
新建文件(File).createNewFile();
}捕获(IOE异常){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
start();
}
@凌驾
公开募捐{
//System.out.println(“日志线程启动”+文件);
while(Run.running){
如果(!写入){
if(Run.logging)
writeToLog();
}
试一试{
睡眠(500);
}捕捉(中断异常e){
Thread.currentThread().interrupt();
打破
}
}
//System.out.println(“日志线程关闭”+文件);
}
公共同步的无效日志(字符串s){
if(Run.logging)
pq.add(s);
}
私有void writeToLog(){
试一试{
写作=真实;
bw=新的BufferedWriter(新的FileWriter(file,true));
而(!pq.isEmpty()){
write(Calendar.getInstance().getTime().toString()+“”+pq.poll());
换行符();
}
bw.flush();
bw.close();
书写=错误;
}catch(异常e){Writing=false;e.printStackTrace();}
}
}
编辑-值得一提的是,在程序的上下文中,它记录了100-1000行
非常感谢
Sam如果后台线程写入磁盘的速度不够快,则(未指定其容量)将增长,直到它包含
整数.MAX\u值
字符串。这对于java堆大小来说太多了
指定容量,以便在队列已满的情况下,调用log方法的线程将在队列日志的某些部分转储到磁盘时等待:
private BlockingQueue<String> pq = new LinkedBlockingQueue<String>(1000);
private BlockingQueue pq=new LinkedBlockingQueue(1000);
在log方法中使用而不是add
,以便日志操作等待而不是引发异常
(您注意到在磁盘上写入时间而不是日志记录时间了吗?如果后台线程写入磁盘的速度不够快,则(未指定其容量)将增长,直到它包含
Integer.MAX\u值
字符串。这对于java堆大小来说太多了
指定容量,以便在队列已满的情况下,调用log方法的线程将在队列日志的某些部分转储到磁盘时等待:
private BlockingQueue<String> pq = new LinkedBlockingQueue<String>(1000);
private BlockingQueue pq=new LinkedBlockingQueue(1000);
在log方法中使用而不是add
,以便日志操作等待而不是引发异常
(您是否注意到您在磁盘上写入时间而不是在日志中写入时间?我相信有
专用缓冲写入程序bw代码>as成员变量导致故障。由于您只在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();}
}
我相信拥有private BufferedWriter bw代码>as成员变量导致故障。由于您只在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();}
}
我刚刚试过这个,但它仍然运行,好主意我刚试过这个,它仍然运行,好主意是的,这部分解决了我的que溢出的问题,但是,在添加之前,让que清除的正确方法是什么呢?因为现在我得到了一个非法状态异常-队列已满谢谢我现在就快到了,唯一的问题是现在我的blockingqueue似乎马上满了,但里面什么都没有?我的坏消息是我的日志变量已关闭..抱歉,但它正在工作谢谢!很高兴听到:)小心不要让它变得更复杂:在某些情况下,使用现有的日志框架会更明智。是的,这部分解决了我的que溢出的问题,但是,在添加之前,让que清除的正确方法是什么呢?因为现在我得到了一个非法状态异常-队列已满谢谢我现在就快到了,唯一的问题是现在我的blockingqueue似乎马上满了,但里面什么都没有?我的坏消息是我的日志变量已关闭..抱歉,但它正在工作谢谢!很高兴听到:)小心不要让它变得更复杂:在某个时候,使用现有的日志框架会更明智。