我正在编写一个java代码来搜索电子邮件地址和密码在一个大的txt文件(6-8Gb)。我已经写了代码,它与200Mb的文本文件工作,并给出了输出。但是,当我输入一个500Mb的文件时,它显示以下错误:
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:331)
at java.nio.charset.CharsetDecoder.decode(CharsetDecoder.java:792)
at regular.expression_fyp.RegularExpression_fyp.main(RegularExpression_fyp.java:56)
Java Result: 1
我是java编程的新手,所以我需要你的帮助来解决这个问题。我该怎么做才能解决这个问题?请给我任何建议,我也附上了我的代码。谢谢你。
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegularExpression_fyp
{
public static void main(String[] argv) throws Exception {
String pattern = "\w[%A-Za-z0-9-]+\%40\w+\.com\w[%A-Za-z0-9]+";
Pattern r = Pattern.compile(pattern);
FileInputStream input = new FileInputStream("E:\test7.txt");
FileChannel channel = input.getChannel();
ByteBuffer bbuf = channel.map(FileChannel.MapMode.READ_ONLY, 0, (int) channel.size());
CharBuffer cbuf = Charset.forName("8859_1").newDecoder().decode(bbuf);
Matcher matcher = r.matcher(cbuf);
if (matcher.find( )) {
System.out.println("Found value: " + matcher.group(0) );
} else {
System.out.println("NO MATCH");
}
}
}
问题是CharBuffer正在转换字节,从而将文件放入堆中。一个更有效的解决方案是为ByteBuffer编写一个包装器,它允许您直接访问内存映射文件。
你可以创建一个CharSquence来封装ByteBuffer来解析整个映射,而不用把它放到堆中。
import java.nio.ByteBuffer;
/**
* Assumes ISO-8859-1 character encoding
*/
public class BufferCharSequence implements CharSequence {
final ByteBuffer bb;
public BufferCharSequence(ByteBuffer bb) {
this.bb = bb;
}
@Override
public int length() {
return bb.limit();
}
@Override
public char charAt(int index) {
return (char) (bb.get(index) & 0xFF);
}
@Override
public CharSequence subSequence(int start, int end) {
bb.limit(start + end);
bb.position(start);
return new BufferCharSequence(bb.slice());
}
}
注意:无论ByteBuffer的容量如何,这将使用<= 24个字节的堆。
正如已经推荐的那样,克服这个问题的一个好方法是以较小的批量从文件加载数据。但是还有另一种方法,您应该了解Java程序是如何分配内存的:
JVM在启动期间被分配有限的内存。让事情变得更复杂的是,JVM内存中有几个不同的区域可以调整,但是作为您的"java.lang. net"。OutOfMemoryError: Java heap space"消息表明,我们对一个称为heap的特定区域感兴趣。
您可以自己指定堆的大小,类似于以下示例,为Java程序授予1G内存:
java -Xmx1024m com.mycompany.MyApplication
如果您的JVM已经在运行,您可以看到指定参数的值,例如通过检查列出启动参数的jps命令的输出,您可以看到熟悉的-Xmx再次指定最大允许堆的值为1GB:
my-machine:demo me$ jps -lvm
6116 com.mycompany.MyClass -Xmx1024m
如果您自己没有指定,则将使用特定于平台的默认值,您可以通过列出java的输出来检查其值,例如使用-XX:+PrintFlagsFinal属性,该属性以字节为单位列出输出,但是,输出列出的堆大小恰好等于1GB或1073741824字节:
my-machine:demo me$ java -XX:+PrintFlagsFinal |grep MaxHeapSize
uintx MaxHeapSize := 1073741824 {product}
因此,尽管批加载可以而且将会有所帮助,但有时通过向它投入更多资源来解决问题更容易。因此,当面对下一个"java.lang. net"时。OutOfMemoryError: Java heap space"错误,您有时可以通过增加JVM可用的资源来绕过它。
您是否尝试减小文件缓冲区大小?也许你应该做一个优化的方法,它看起来像你的缓冲区被6Gb的文件完全加载,这就是你的应用程序。
您可以尝试增加jvm的HEAP大小。您可以使用java -Xms[initial heap size] -Xmx[maximum heap size]
感谢大家的辛勤付出!因为我使用netbeans,我找到了另一种方法(今天)。根据我在项目属性和运行中,我增加了-Xmx1000m的虚拟机选项。现在我的程序运行得很好。但是我想知道这是否会导致我将来出现任何错误,因为我想使这个程序可执行。所以这应该也能在其他windows操作系统上运行。这个变化以后会给我带来什么问题吗?