1

プログラムのバックグラウンド ロギング スレッドをコーディングしました。クラスがロガーを必要とする場合、ロガーはスレッドプールからプルされるため、ファイル名ごとに実行されるログは 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();}
}



}

編集 - プログラムのコンテキストでは、数百から数千行をログに記録していることにも言及する価値があります

どうもありがとうサム

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 に答える