CharBuffer在内存映射的ByteBuffer之上,而不使用大量的堆空间



我正在编写一个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操作系统上运行。这个变化以后会给我带来什么问题吗?

相关内容

  • 没有找到相关文章

最新更新