为什么Java Grep会因OutOfMemoryError崩溃?

问题描述

| 我或多或少地运行以下代码 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)
    

解决方法

        您没有做错任何事。 问题在于应用程序将整个文件映射到内存中,然后创建该文件的第二个堆内副本。尽管映射文件确实使用了JVM虚拟地址空间的一部分,但它并没有占用堆空间。 它是第二个副本,并且创建它的过程实际上正在填充堆。第二个副本包含扩展为16位字符的文件内容。考虑到如何对堆空间进行分区,大约4亿个字符(8亿个字节)的连续数组对于1Gb堆来说太大了。 简而言之,应用程序只是在使用过多的内存。 您可以尝试增加最大堆大小,但是真正的问题是应用程序在管理内存的方式上过于简单。 要做的另一点是您正在运行的应用程序是一个旨在说明如何使用NIO的示例。它并非旨在作为通用的生产质量实用程序。您需要相应地调整您的期望。     ,        可能是因为400Mb文件已加载到CharBuffer中,所以它以UTF16编码占用的内存是原来的两倍。因此,它不会为模式匹配器留下太多内存。 如果您正在使用Java的最新版本,请尝试-XX:+ UseCompressedStrings,以便它在内部将字节表示为字节数组,并且占用较少的内存。您可能必须将CharBuffer放入字符串中。 所以例外是
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,lim,cap,new char[cap],0);
这意味着它无法创建文件大小的“ 3”数组。 如果要在Java中grep大文件,则需要找到某种接受
Reader
的算法。标准的Java库没有这种功能。     ,        我想假设是因为给定的类将整个文件加载到内存中。我不确定,因为我不知道Java NIO类。我可能会怀疑像
MappedByteBuffer
CharBuffer
这样的类。 堆栈跟踪可能能够告诉您它的来源。