Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/391.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 读取非常大的文件时出现异常>;300 MB_Java_File - Fatal编程技术网

Java 读取非常大的文件时出现异常>;300 MB

Java 读取非常大的文件时出现异常>;300 MB,java,file,Java,File,我的任务是以读写模式打开一个大文件,我需要通过搜索起始点和结束点来搜索文件中的部分文本。 然后我需要将搜索到的文本区域写入一个新文件,并从原始文件中删除该部分 以上过程我会多做几次。 因此,我认为对于这些过程,通过CharBuffer将文件加载到内存将很容易,并且可以通过MATCHER类轻松搜索。 但是我在阅读时遇到了HeapSpace异常,尽管我通过执行下面的命令增加到了900MB java-Xms128m-Xmx900m可读大文件 我的代码是 FileChannel fc = new Fil

我的任务是以读写模式打开一个大文件,我需要通过搜索起始点和结束点来搜索文件中的部分文本。 然后我需要将搜索到的文本区域写入一个新文件,并从原始文件中删除该部分

以上过程我会多做几次。 因此,我认为对于这些过程,通过CharBuffer将文件加载到内存将很容易,并且可以通过MATCHER类轻松搜索。 但是我在阅读时遇到了HeapSpace异常,尽管我通过执行下面的命令增加到了900MB java-Xms128m-Xmx900m可读大文件 我的代码是

FileChannel fc = new FileInputStream(fFile).getChannel();
CharBuffer chrBuff = Charset.forName("8859_1").newDecoder().decode(fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()));
对于上述代码,每个 建议我说这是个坏主意 将所有内容加载到内存中,如果 文件大小为300 MB意味着 600MB由于字符集

以上是我的任务,现在给我建议一些有效的方法。 请注意,我的文件大小将更大,使用JAVA我只需要做这些事情


先谢谢你

您的搜索模式是否匹配多行?如果不是,那么最简单的解决方案是逐行读取:)。真的很简单


但是如果搜索模式匹配多行,那么您需要让我们知道,因为逐行搜索不起作用。

您的搜索模式匹配多行吗?如果不是,那么最简单的解决方案是逐行读取:)。真的很简单


但是如果搜索模式匹配多行,那么您需要让我们知道,因为逐行搜索将不起作用。

您肯定不希望使用Java将300MB文件加载到单个大缓冲区中。您处理大型文件的方式应该比使用普通I/O更有效,但是当您对映射到内存中的整个文件运行
Matcher
时,很容易耗尽内存

首先,代码内存将文件映射到内存中。。。当文件
mmap
插入虚拟地址空间时,这将在虚拟地址空间中消耗300兆内存,尽管这在堆之外。(请注意,300兆的虚拟地址空间被占用,直到
MappedByteBuffer
被垃圾收集。请参阅下面的讨论。的JavaDoc警告您这一点。)接下来,您创建一个
ByteBuffer
备份文件。这应该没问题,因为它只是
mmap
ed文件的一个“视图”,因此应该占用最少的额外内存。它将是堆中的一个小对象,带有指向堆外一个大对象的“指针”。接下来,您将其解码为
CharBuffer
,这意味着您对300 MB缓冲区进行了复制,但由于
char
是2个字节,因此您进行了600 MB复制(在堆上)

为了响应一条注释,并查看JDK源代码,当您按OP的方式调用
map()
时,实际上是将整个文件映射到内存中。查看openJDK 6 b14 Windows本机代码
sun.nio.ch.FileChannelImpl.c
,它首先调用,然后调用。查看此源代码,如果您要求将整个文件映射到内存中,此方法将完全按照您的要求执行。引用MSDN:

映射文件使文件的指定部分在 调用进程的地址空间

对于大于地址空间的文件,只能映射一小部分 一次读取文件数据的一部分。第一个视图完成后,可以取消映射并 映射新视图

OP调用map的方式是,文件的“指定部分”是整个文件。这不会导致堆耗尽,但会导致虚拟地址空间耗尽,这仍然是一个OOM错误。这会彻底杀死您的应用程序,就像耗尽堆一样

最后,当您制作一个
匹配器
时,
匹配器
可能会制作这个600 MB
字符缓冲区
的更多副本,具体取决于您如何使用它。哎哟这是少量对象使用的大量内存!给定一个
Matcher
每次调用
toMatchResult()
,您都将创建
字符串的
副本,复制整个
。另外,每次调用
replaceAll()
,充其量只能复制整个
CharBuffer
字符串。在最坏的情况下,您将生成一个
StringBuffer
,它将缓慢扩展到
replaceAll
结果的完整大小(对堆施加大量内存压力),然后从中生成一个
String

因此,如果对300 MB文件调用
Matcher
上的
replaceAll
,找到匹配项,则首先生成一系列更大的
StringBuffer
s,直到得到一个600 MB的文件。然后您将制作此
StringBuffer
String
副本。这可能会快速而容易地导致堆耗尽

底线是:
Matcher
s不适合处理非常大的缓冲区。你可以很容易地,而且不需要计划,制作很多非常大的物体。我是在做一些与您正在做的事情非常相似的事情时发现这一点的,并且遇到内存耗尽的情况,然后查看
Matcher
的源代码

注意:没有
unmap
调用。调用后,由
MappedByteBuffer
绑定的堆外虚拟地址空间将被固定在那里,直到
MappedByteBuffer
被垃圾收集。因此,在
MappedByteBuffer
被垃圾收集之前,您将无法对文件执行某些操作(删除、重命名等)。如果在不同的文件上调用map的次数足够多,但堆中没有足够的内存压力来强制使用garb
FileChannel fc = new FileInputStream(fFile).getChannel();
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());

CharBuffer chrBuff = mbb.asCharBuffer();