【问题标题】:Java does not free memoryJava 不释放内存
【发布时间】:2013-02-19 17:23:15
【问题描述】:

我有一个守护程序,它读取文件的内容,然后将其压缩并写入更小的 .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);
}

【问题讨论】:

  • 我发现的一件事是,你永远不会结束 while 循环,即 while(true)
  • 顺便说一句,如果未使用,java 不会立即删除内存。由 VM 来释放内存
  • 你怎么知道它一直在分配内存?您是否遇到内存不足错误?代码中的 System.gc() 不需要真正 任何事情; JVM 可以将其解释为仅仅是一个提示。
  • 使用 jvisualvm(或其他分析器)分析内存分配并找到它分配未释放内存的位置。
  • @cIph3r - 大概所有东西都包装在一个抛出异常或类似东西的方法中; Thread.sleep() 应该避免过多的 CPU 使用。

标签: java file memory


【解决方案1】:

你煮过头了。所有这些 null 设置和 gc()-calling 实际上并没有帮助,而且您需要的刷新和关闭次数是您真正需要的数倍。此外,您根本不需要使用 Readers 和 Writers。所有这些都可以简化为:

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);
}

我无法理解您的评论“会将内容发送到另一个线程,因此我需要逐行阅读”。这段代码没有线程,也不需要逐行输入。

我也很好奇它如何与生成输入文件的任何东西交互。我认为你应该重命名输入文件,并在你决定复制它后立即创建一个新的空文件,而不是在复制步骤之后。

【讨论】:

  • 谢谢,您的代码实际上对内存消耗的观点有很大帮助。您的最后一段也很有帮助,我结束了对原始 Python 代码(输入)的编辑以直接写入 tgz 文件,因此同时写入/读取没有问题。 Python 还写入另一个文件,基本上是“我已经完成了文件 X”,因此 Java 知道它可以打开和处理。不过还是谢谢
【解决方案2】:

对象不会因为不再被引用而从内存中释放。 JVM 决定何时运行其“垃圾收集”,从而释放内存。但它通常不会运行垃圾收集,除非它需要。更多信息,您可以查看this page about the topic

您可以调用 System.gc() 来显式调用垃圾收集器(链接中的第 7 点),但它不必运行。

【讨论】:

    【解决方案3】:

    System.gc() 发送垃圾回收请求。运行时决定是执行它还是忽略所述请求。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-29
      • 2011-06-30
      • 2016-09-14
      • 2015-08-19
      • 2012-05-15
      • 2018-01-26
      • 2011-09-30
      相关资源
      最近更新 更多