1

编辑:

我最终使用 FileInputStream 只保存我感兴趣的位置的索引,而不是将文件加载到内存(在需要时更新位置)。

如果您每次持有较少的数据,则可以将其配置为使用更少的内存(更多的内存访问),或者如果您持有更多的数据,则使用更多的内存(更少的内存访问)。

假设您正在循环通过一些代码,您可以使用响应时间来调整缓冲区。

虽然我确信可以使用非阻塞 I\O 来改进这一点,但我发现它并不直观,我已经求助于使用我可以轻松控制的更简单的东西。


我有一个大学项目,涉及比较大文件的字节序列。

为了快速完成这项工作,我决定将所有文件加载到内存中(文件总共大约 500mb)并在将信息存储在一个小数据库中提取的同时进行比较(查询不经常完成)。

我已经将“File”类扩展为一个新类“MappedFile”,其中每个 Mappedfile 都有一个字节数组(在构造时创建)保存文件的字节。

这是整个 MemFile 类:

public class MemFile extends File{

private String md5;
private byte[] bytes;

public MemFile(String pathname) {
    super(pathname);
}

public byte[] getBytes(){
    if (this.bytes == null){
        this.bytes = FileUtils.getFileBytes(this);
    }
    return this.bytes;
}

public String getMD5(){
    if (this.md5 == null){
        this.md5 = MD5Generator.generate(this.getAbsolutePath());
    }
    return this.md5;
    }
}

我持有这些列表,我从大字节数组中提取较小的数组,然后在其他文件中查找它们。

我的问题是,当我只使用 500mb 文件的一小部分时,我的内存很快就会耗尽(我已经用 2gb 的内存启动了 eclipse)

这是完成这项工作的现实方法还是我将许多东西加载到内存中?

是否可以选择以某种方式监视虚拟内存?

  • 数据库很小,当事情变慢并即将再次崩溃时包含 4 个条目,这打破了我喜欢 Java 用于此类项目的梦想(这是强制性的)。
4

2 回答 2

2

我会使用内存映射文件。这些不使用太多堆内存并且可以更快地加载。他们只是使用虚拟内存,所以只要你有 64 位,你就可以加载数千个这样的问题。

FileChannel fc = new FileInputStream(fileName).getChannel();
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());

您可以继续对所有文件执行此操作,它只会使用几 KB 的堆。注意:这适用于最大 2 GB 的文件(大于您必须部分映射的文件)

于 2013-06-15T14:19:43.833 回答
2

JDK 已经有了你想要的:FileChannel#map().

更重要的是,它返回一个MappedByteBuffer扩展ByteBuffer的 ,您可以在其上使用 比较内容.equals()

使用 Java 7,它很简单:

final FileChannel fc = FileChannel.open(Paths.get("/path/to/file"),
    StandardOpenOption.READ);
final ByteBuffer buf = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());

(哦,它实现了Closeable,因此AutoCloseable

于 2013-06-15T14:20:40.057 回答