有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java确定合适的缓冲区大小

我用的是ByteBuffer。allocateDirect()分配一些缓冲内存,用于将文件读入内存,然后最终对文件字节进行散列,并从中获取文件散列(SHA)。输入文件的大小范围很大,从几KB到几GB不等

关于选择缓冲区大小的问题,我已经读了好几篇文章和页面(甚至还有一些)。一些人建议尝试选择本机文件系统使用的一个,以尽量减少对部分块等执行读取操作的机会。例如4100字节的缓冲区和默认为4096的NTFS,因此额外的4位将需要单独的读取操作,这是非常浪费的

因此,坚持使用2、1024、2048、4096、8192等的幂次。我看到一些建议缓冲区的大小为32KB,另一些建议缓冲区的大小为输入文件的大小(可能适合小文件,但大文件呢?)

坚持使用本地块大小的缓冲区有多重要?从现代意义上讲(假设现代SATA驱动器或更好的驱动器上至少有8Mb的驱动器缓存,以及其他现代操作系统优化I/O的“魔法”)缓冲区大小有多重要,我应该如何最好地确定将我的设置为什么大小?我可以静态地设置它,或者动态地确定它?谢谢你的洞察力


共 (1) 个答案

  1. # 1 楼答案

    回答你的直接问题:(1)文件系统倾向于使用2的幂,所以你也要这样做。(2) 工作缓冲区越大,任何大小错误的影响就越小

    正如您所说,如果分配4100,实际块大小为4096,则需要两次读取来填充缓冲区。相反,如果你有一个1000000字节的缓冲区,那么一个块高或低并不重要(因为需要245个4096字节的块来填充这个缓冲区)。此外,更大的缓冲区意味着操作系统有更好的机会对读取进行排序

    也就是说,我不会用NIO来做这个。相反,我会使用一个简单的BufferedInputStream,可能会为我的read()使用1k缓冲区

    NIO的主要好处是不让数据进入Java堆。例如,如果您正在读写文件,使用InputStream意味着操作系统将数据读入JVM管理的缓冲区,JVM将数据复制到堆内缓冲区,然后再次将其复制到堆外缓冲区,然后操作系统读取堆外缓冲区以写入实际的磁盘块(通常会添加自己的缓冲区)。在这种情况下,NIO将消除本机堆拷贝

    然而,要计算散列,需要在Java堆中有数据,以及MacSPIwill move it there。因此,NBI不会让数据远离堆,在我看来,“旧IO”更容易编写

    只是别忘了InputStream.read()并不是能保证读取你所要求的所有字节