我或多或少地开始使用以下代码
http://download.oracle.com/javase/1.4.2/docs/guide/nio/example/Grep.java
我正在使用以下VM参数
-Xms756m -Xmx1024m
它在400mb文件上与OutOfMemory崩溃。我做错了什么?
堆栈追踪:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.nio.HeapCharBuffer.<init>(Unknown Source)
at java.nio.CharBuffer.allocate(Unknown Source)
at java.nio.charset.CharsetDecoder.decode(Unknown Source)
at com.alluvialtrading.tools.Importer.<init>(Importer.java:46)
at com.alluvialtrading.tools.ReutersImporter.<init>(ReutersImporter.java:24)
at com.alluvialtrading.tools.ReutersImporter.main(ReutersImporter.java:20)
答案 0 :(得分:5)
你没有做错任何事。
问题是应用程序将整个文件映射到内存中,然后创建该文件的第二个堆内副本。映射文件不占用堆空间,但它确实使用了JVM的部分虚拟地址空间。
这是第二个副本,以及创建实际填充堆的过程。第二个副本包含扩展为16位字符的文件内容。考虑堆空间的分区方式,大约4亿个字符(8亿字节)的连续数组对于1Gb堆来说太大了。
简而言之,应用程序只是使用了太多内存。
您可以尝试增加最大堆大小,但真正的问题是应用程序在管理内存方面过于简单。
要做的另一点是您运行的应用程序是一个用于说明如何使用NIO的示例。它不是设计用于通用的,生产质量的实用程序。您需要相应地调整您的期望。
答案 1 :(得分:1)
可能是因为400Mb文件被加载到CharBuffer中,所以它需要两倍的UTF16编码内存。因此它不会为模式匹配器留下太多内存。
如果您正在使用最新版本的java,请尝试-XX:+ UseCompressedStrings,以便它在内部将字符串表示为字节数组并消耗更少的内存。您可能必须将CharBuffer放入String中。
所以例外是
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.nio.HeapCharBuffer.<init>(HeapCharBuffer.java:57)
at java.nio.CharBuffer.allocate(CharBuffer.java:329)
at java.nio.charset.CharsetDecoder.decode(CharsetDecoder.java:777)
at Grep.grep(Grep.java:118)
at Grep.main(Grep.java:136)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
问题的行是HeapCharBuffer的构造函数:
super(-1, 0, lim, cap, new char[cap], 0);
这意味着它无法创建文件大小的char
数组。
如果你想在java中grep大文件,你需要找到一些接受某种Reader
的算法。标准java库没有这样的功能。
答案 2 :(得分:0)
我会假设因为给定的类将ENTIRE文件加载到内存中。正是我不确定的地方,因为我不知道Java NIO类。我怀疑,MappedByteBuffer
和CharBuffer
这样的课程可能会成为问题。
堆栈跟踪可能会告诉您它的来源。