-1

这是有罪的代码:

// Demo the java.lang.OutOfMemoryError: Java heap space error.

    import java.util.*;

    public class Bozo {

      void TstReadFile() {
        SubBozo sb = new SubBozo();
        sb.readFile();
      }

   public static void main(String[] args) {
      Bozo b = new Bozo();
      b.TstReadFile();
    }
  }


/** Read in the observing list file. */

import java.io.*;
import java.util.*;

public class SubBozo {

  public boolean readFile() {

    int lineCt = 0;          // Count the lines read in observingList.

    long heap,
         heapMaxSize,
         heapFreeSize;

    String s = "Unstarted";

    FileInputStream fis = null;
    DataInputStream in = null;
    BufferedReader br = null;

    try {
      fis = new FileInputStream("../data/observingList");
      in = new DataInputStream(fis);
      br = new BufferedReader(new InputStreamReader(in));
    } catch (Exception e) {
      System.out.println("Couldn't open ../data/observingList because " +
                         e.getMessage());
    }

    boolean go = true;
    while (go) {
      try {
        s = br.readLine();  // Lines should not be longer than say 256 characters.
      } catch (Exception e) {
        System.out.println("Couldn't read ../data/observingList because " +
                           e.getMessage());
        heap = Runtime.getRuntime().totalMemory();
        heapMaxSize = Runtime.getRuntime().maxMemory();
        heapFreeSize = Runtime.getRuntime().freeMemory();
        System.out.println("" + lineCt + ") " + "Total Memory (MB): " +
                           (heap / 1048576) + "\n  Heap Max Size (MB): " +
                           (heapMaxSize / 1048576) +
                           "\n  Heap Free Size (MB): " +
                           (heapFreeSize / 1048576));
        go = false;
      }

      if ((lineCt++ % 1000) == 0) {
        System.gc();
        heap = Runtime.getRuntime().totalMemory();
        heapMaxSize = Runtime.getRuntime().maxMemory();
        heapFreeSize = Runtime.getRuntime().freeMemory();
        System.out.println("" + lineCt + ") " + "Total Memory (MB): " +
                           (heap / 1048576) + "\n  Heap Max Size (MB): " +
                           (heapMaxSize / 1048576) +
                           "\n  Heap Free Size (MB): " +
                           (heapFreeSize / 1048576));
      }
    }

    try {
      br.close();
      in.close();
      fis.close();
    } catch (Exception e) {
      System.out.println("Couldn't close the input file stream because " +
                         e.getMessage());
    }
    return true;
  }
}

运行时,使用以下命令:

星云:finderChart/src java Bozo

它会引发内存不足错误。这是打印输出:

1) 总内存 (MB): 119 堆最大大小 (MB): 1776 堆可用大小 (MB): 118

1001) 总内存 (MB): 119 堆最大大小 (MB): 1776 堆可用大小 (MB): 119

2001) 总内存 (MB):119 堆最大大小 (MB):1776 堆可用大小 (MB):119

3001) 总内存 (MB): 119 堆最大大小 (MB): 1776 堆可用大小 (MB): 119

线程“主”java.lang.OutOfMemoryError 中的异常:java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:100) 处 java.util.Arrays.copyOf(Arrays.java:2882) 处的 Java 堆空间。在 java.io.BufferedReader.readLine(BufferedReader.java:345) 在 java.io.BufferedReader.readLine(BufferedReader) 的 java.lang.StringBuffer.append(StringBuffer.java:306) 的 AbstractStringBuilder.append(AbstractStringBuilder.java:515) .java:362) 在 SubBozo.readFile(SubBozo.java:34) 在 Bozo.TstReadFile(Bozo.java:10) 在 Bozo.main(Bozo.java:15)

现在是奇怪的部分,但我怀疑你已经看过了。JVM 每 1000 行打印一次它的内存使用情况。它没有耗尽内存。

当错误被抛出时,它错过了捕获:

尝试 {

 s = br.readLine();

} 捕捉(异常 e){

 System.out.println("Couldn't read ../data/observingList because " 
 ...

}

所以让我们尝试增加内存:java -Xmx1024m Bozo

相同的结果,所以我不会重复它。

发生的事情是正在读取的文件 obasrvingList 中有一些很长(> 2048 字节)的行。这吓坏了 Java,但直到我尝试在 Vim 中编辑文件并发现 vim 无法编辑它时,才发现对于一般的文本阅读器来说,异常长的行是一个问题。

TIA

汤姆

4

2 回答 2

3

你没有问任何问题,但这里有一些答案:

当错误被抛出时,它错过了捕获:

因为你在抓ExceptionOutOfMemoryError不是在扩展它。感谢上帝,因为您在记录异常时忽略了堆栈跟踪:

System.out.println("Couldn't read ../data/observingList because " +
                       e.getMessage());

而是始终使用:

e.printStackTrace();

更好- 使用一些日志框架。

它没有耗尽内存。

嗯,是的。它尝试分配一个太大的数组(例如:您有 50 MiB 可用空间,它尝试分配 60 MiB)。这就是StringBuffer工作原理——将内部数组的大小加倍,同时暂时保留对旧数组和新数组的引用。

发生的事情是正在读取的文件 obasrvingList 中有一些很长(> 2048 字节)的行。这吓坏了 Java,但直到我尝试在 Vim 中编辑文件

我可以向你保证,2048 个字符对于 JVM 来说不算什么。我怀疑有问题的行至少有几百万个字符......甚至也无法打开该文件(可能是有史以来最优化的编辑器),所以这些行可能非常长。

此外,我对整体代码质量几乎没有建议(比如吞下​​异常并返回控制循环falsego布尔标志)——但这更适合http://codereview.stackexchange.com

于 2012-04-14T19:45:12.850 回答
1

BufferredReader.readLinenull如果没有数据则返回,它不会抛出异常。因此,将您的代码更改为:

 while (go) {
     s = br.readLine();
     if (s = null) break;

而不是处理异常。这就是为什么您的代码永远不会离开循环并且可能正在尝试无限分配内存的原因。

于 2012-04-14T19:39:54.007 回答