7

我正在尝试将 2.5GB 的 txt 文件读入我的应用程序。我正在运行 Win7 x64 并且有 43GB 的可用内存(超过 64GB)。我尝试使用 -Xmx -XX:MaxParmSize -XX:ParmSize 等。这些都不会影响错误。我还能尝试什么?这个错误看起来很奇怪,因为我当然有足够的可用堆空间。

Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit
    at java.util.Arrays.copyOf(Unknown Source)
    at java.lang.AbstractStringBuilder.expandCapacity(Unknown Source)
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(Unknown Source)
    at java.lang.AbstractStringBuilder.append(Unknown Source)
    at java.lang.StringBuilder.append(Unknown Source)
    at j.utilities.IO.loadString(IO.java:187)
    at j.utilities.IO.loadString(IO.java:169)
    at city.PreProcess.main(PreProcess.java:78)

我在跑步

java version "1.7.0_09"
Java(TM) SE Runtime Environment (build 1.7.0_09-b05)
Java HotSpot(TM) 64-Bit Server VM (build 23.5-b02, mixed mode)

提前非常感谢。

============== 答案===============

好的,我刚刚测试过

StringBuilder sb = new StringBuilder();
for ( int i=1; i<Integer.MAX_VALUE; i++ )
    sb.append("x");

并得到

Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit
at java.util.Arrays.copyOf(Unknown Source)
...

因此,实际上是 StringBuilder 试图构建一个大于 Integer.MAX_VALUE 的数组。

如有兴趣

StringBuilder sb = new StringBuilder();
int i=1;
try {
    for ( ; i<Integer.MAX_VALUE; i++ )
        sb.append("x");
} catch ( OutOfMemoryError e ) {
    System.out.println(i); // OUTPUT: 1207959551
    System.out.println(Integer.MAX_VALUE); // OUTPUT: 2147483647
}

使用 StringBuilder,您可以累积 1,207,959,550 个字符 - 远远少于 Integer.MAX_VALUE。

4

4 回答 4

10

您正在尝试分配一个太大的数组。这是因为您正在尝试创建一个非常长的字符串。由于数组由整数索引,因此数组不能有多个Integer.MAX_VALUE元素。即使您的堆大小非常大,您也无法分配包含多个Integer.MAX_VALUE元素的数组,因为您无法使用Integer. 请参阅Java 数组是否有最大大小?更多细节。

于 2012-12-07T23:50:22.273 回答
3

您可以创建一个新的 StringBuilder 大小,例如

    StringBuilder sb = new StringBuilder(Integer.MAX_VALUE);

问题是您试图读取的文件比 StringBuilder 数组中的文件大。您有多种选择,例如:

1)你真的需要一次将整个文件读入内存吗?如果是这样,您必须将其读入多个 StringBuilders。

2) 按顺序处理文件。

3) 将其读入压缩结构,在需要的时候解压需要的部分。

于 2012-12-08T00:42:19.160 回答
0

您应该查看 java 命令的 -Xmsn 选项。

它指定内存分配池的初始大小。

编辑:我看到你已经这样做了。

于 2012-12-07T23:53:05.007 回答
0

您可以将字符串缓冲区中的数据保存List<String>在定义间隔中并清除StringBuffer.

于 2014-03-31T22:11:01.553 回答