0

ファイルのコンテンツを読み取り、それを圧縮して小さな .tar.gz ファイルに書き込むデーモン プログラムがあります。

なんらかの理由で、すべての使用済みメモリを解放した (または解放したと思われる) 後でも、Java はメモリを割り当て続けます。私のコード/推論の何が問題になっていますか?

FileOutputStream fos    = null;
GZIPOutputStream gzipos = null;
OutputStreamWriter osw  = null;

BufferedWriter bw = null;
while (true) {
    if (f.length() != 0) {
        if (outputfile == null) {
            outputfile = outputfileroot + "_" + outputPart + ".tar.gz";

            fos = new FileOutputStream(outputfile);
            gzipos  = new GZIPOutputStream(fos);
            osw = new OutputStreamWriter(gzipos);
            bw  = new BufferedWriter(osw);
        }
        else if (new File(outputfile).length() > maxLengthOutputFile) {
            bw.flush();
            osw.flush();
            gzipos.flush();
            fos.flush();
            bw.close();
            osw.close();
            gzipos.close();
            fos.close();

            bw  = null;
            osw = null;
            gzipos  = null;
            fos = null;

            System.gc();

            System.out.println("Finished writing " + outputfileroot + "_" + outputPart + ".tar.gz");

            outputfile = outputfileroot + "_" + ++outputPart + ".tar.gz";
            fos     = new FileOutputStream(outputfile);
            gzipos  = new GZIPOutputStream(fos);
            osw     = new OutputStreamWriter(gzipos);
            bw      = new BufferedWriter(osw);
        }

        /**
         * Read the entire file
         */
        BufferedReader br = new BufferedReader(new FileReader(f));
        String line;
        while ((line = br.readLine()) != null) {
            // will send the content to another thread, so I need to read it line by line
            bw.write(line + "\r\n");
        }
        br.close();
        br = null;
        bw.flush();

        /**
         * Empty it
         */
        FileWriter fw = new FileWriter(f);
        fw.write("");
        fw.flush();
        fw.close();
        fw = null;
    }

    Thread.sleep(1000);
}
4

3 に答える 3

2

あなたはこれを焼き過ぎています。null 設定とgc()-calling は実際には役に立たず、実際に必要な数倍のフラッシュとクローズがあります。また、リーダーとライターを使用する必要はまったくありません。これに減らすことができるすべて:

GZIPOutputStream gzipos = null;
while (true)
{
    if (f.length() != 0)
    {
        if (outputfile == null)
        {
            outputfile = outputfileroot + "_" + outputPart + ".tar.gz";
            gzipos = new GZIPOutputStream(new FileOutputStream(outputfile));
        }
        else
        {
            if (new File(outputfile).length() > maxLengthOutputFile)
            {
                gzipos.close();
                System.out.println("Finished writing " + outputfileroot + "_" + outputPart + ".tar.gz");
                outputfile = outputfileroot + "_" + ++outputPart + ".tar.gz";
                gzipos = new GZIPOutputStream(new FileOutputStream(outputfile));
            }
        }

        /**
         * Read the entire file
         */
        InputStream in = new FileInputStream(f);
        byte[] buffer = new byte[8192];
        int count;
        while ((count = in.read(buffer)) > 0)
        {
            gzipos.write(buffer, 0, count);
        }
        in.close();
        gzipos.flush();
        /**
         * Empty it
         */
        f.createNewFile();
    }
    Thread.sleep(1000);
}

「コンテンツを別のスレッドに送信するので、1行ずつ読む必要がある」というコメントの意味がわかりません。このコードにはスレッドがなく、1 行ずつ入力する必要はありません。

また、これが入力ファイルを生成するものとどのように相互作用するかについても興味があります。コピー手順の後ではなく、コピーすることに決めたらすぐに、入力ファイルの名前を変更し、その場所に新しい空のファイルを作成する必要があると思います。

于 2013-02-19T23:18:19.787 に答える
1

オブジェクトが参照されなくなったからといって、オブジェクトがメモリから解放されるわけではありません。JVM は、メモリを解放する「ガベージ コレクション」をいつ実行するかを決定します。ただし、通常、必要がない限り、ガベージ コレクションは実行されません。詳細については、トピックに関するこのページを参照してください。

ガベージ コレクターを明示的に呼び出すために呼び出すことができますがSystem.gc()(リンクのポイント #7)、実行する必要はありません。

于 2013-02-19T17:26:36.860 に答える
0

System.gc()ガベージ コレクションのリクエストを送信します。ランタイムは、それを実行するか、その要求を無視するかを決定します。

于 2013-02-19T17:27:08.533 に答える