【问题标题】:Java heap space of BlueJBlueJ 的 Java 堆空间
【发布时间】:2017-04-12 06:41:49
【问题描述】:

BlueJ 的 Java 堆空间有问题。 我编写了一个程序,它将 .txt 读入字符串并遍历字符串的所有字符并做一些事情(猜想这不是很重要)。一些 .txt 文件非常大(大约 2 亿)。 如果我尝试使用这些 .txt 执行程序,我会得到这个“线程中的异常”AWT-EventQueue-0“java.lang.OutOfMemoryError:Java 堆空间”错误代码。我将 bluej.def 中的 bluej.windows.vm.args 和 bluej.windows.vm.args 增加到 8gb。它仍然不起作用。但我实际上猜想即使是 2 亿个字符的字符串也不会超过这个限制。 这是我在 .txt 中阅读的代码

try
    {
        FileReader reader = new FileReader(input.getText());
        BufferedReader bReader = new BufferedReader(reader);
        String parcour = "";
        String line = bReader.readLine();
        while(line != null)
        {
            parcour += line;
            line = bReader.readLine();            
        }

input.getText() 获取文件路径。 我将非常感谢您的回答。谢谢 :) - Cyaena

【问题讨论】:

  • 您将整个文件存储在parcour 变量中。这会吃掉很多内存。另外,在将数据附加到字符串时考虑使用StringBuilder
  • 但实际上一个字符串不应该吃那么多内存,不是吗?我必须使用 StringBuilder 有什么好处?我该如何大致设置?
  • 我不是解释内存使用的合适人选,而是存储 2 亿。记忆中的字符听起来不是很有希望。在循环中连接字符串时,StringBuilder 更快。你想用这 2 亿行做什么?也许这可以帮助你:stackoverflow.com/questions/10202905/…更多关于内存使用的信息:javamex.com/tutorials/memory/string_memory_usage.shtml
  • 好吧,我实际上猜它是 200MB,可能会更多,但不是 8GB。这是一场比赛,其中有一些例子。较小的例子没有任何问题。我的算法运行良好,运行时也不错。但是对于这些很棒的文件,是的,我得到了这个错误。
  • 也许如果您解释您的用例,其他人可以帮助解决问题。您不能在 while 循环中处理一行而不是将所有内容都存储在变量中吗?

标签: java heap-memory ram bluej


【解决方案1】:

在下面的解释中,只有数据的普通内存在范围内。结构所需的所有额外内存都被忽略了。它更像是一个概览,作为一个深入的细节视图。

内存在那些行被吃掉

String parcour = "";
...
String line = bReader.readLine();
...
parcour += line;

parcour += line 行编译成类文件为

new StringBuilder().append(parcour).append(line).toString()

假设 parcour 包含大小为 10 MB 的字符串,line 的大小为 2 MB。那么parcour += line; 期间分配的内存将(大致)

// creates a StringBuilder object of size 12 MB
new StringBuilder().append(parcour).append(line)

// the `.toString()` would generate a String object of size 12 MB
new StringBuilder().append(parcour).append(line).toString()

在将新创建的字符串分配给parcour 之前,您的代码需要大约 34 MB。

parcour                            = 10 MB
the temporary StringBuilder object = 12 MB
the String fromStringBuilder       = 12 MB
------------------------------------------
total                                34 MB

一个小演示 sn-p 显示 OutOfMemoryException 比您当前预期的要早得多。

OOMString.java

class OOMString {
    public static void main(String[] args) throws Exception {
        String parcour = "";
        char[] chars = new char[1_000];
        String line = new String(chars);
        while(line != null)
        {
            System.out.println("length = " + parcour.length());
            parcour += line;
        }        
    }
}

OOMStringBuilder.java

class OOMStringBuilder {
    public static void main(String[] args) throws Exception {
        StringBuilder parcour = new StringBuilder();
        char[] chars = new char[1_000];
        String line = new String(chars);
        while(line != null)
        {
            System.out.println("length = " + parcour.length());
            parcour.append(line);
        }        
    }
}

两个 sn-ps 都做同样的事情。他们将 1,000 个字符的字符串添加到 parcour 直到 OutOfMemoryException 被抛出。为了加快速度,我们将堆大小限制为 10 MB。

java -Xmx10m OOMString的输出

length = 1048000
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

java -Xmx10m OOMStringBuilder的输出

length = 2052000
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

当您执行代码时,您会注意到OOMStringOOMStringBuilder 需要更多的失败时间(即使长度更短)。

您还需要记住,单个字符有两个字节长。如果您的文件包含 100 个 ASCII 字符,则它们会占用 200 个字节的内存。

也许这个小演示可以为你解释一下。

【讨论】:

    【解决方案2】:

    BlueJ 和堆空间错误也有一些问题。就我而言,打开终端会使整个应用程序崩溃。我怀疑这与生成大量输出有关,类似于您的大字符串。就我而言,我不小心在某处创建了一个无限循环,破坏了终端窗口。

    我不得不删除所有属性文件。现在 BlueJ 再次工作并且不再给出 OutOfMemoryErrors。 我希望这对其他情况也有帮助。

    【讨论】:

      猜你喜欢
      • 2021-09-09
      • 1970-01-01
      • 2011-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-19
      • 2011-10-24
      • 1970-01-01
      相关资源
      最近更新 更多