Sti*_*tig 8 java io performance fileinputstream
如果我将文件中的字节读入byte [],我发现当数组大约1 MB而不是128 KB时,FileInputStream的性能会更差.在我测试的2个工作站上,它几乎是128 KB的两倍.这是为什么?
import java.io.*;
public class ReadFileInChuncks
{
public static void main(String[] args) throws IOException
{
byte[] buffer1 = new byte[1024*128];
byte[] buffer2 = new byte[1024*1024];
String path = "some 1 gb big file";
readFileInChuncks(path, buffer1, false);
readFileInChuncks(path, buffer1, true);
readFileInChuncks(path, buffer2, true);
readFileInChuncks(path, buffer1, true);
readFileInChuncks(path, buffer2, true);
}
public static void readFileInChuncks(String path, byte[] buffer, boolean report) throws IOException
{
long t = System.currentTimeMillis();
InputStream is = new FileInputStream(path);
while ((readToArray(is, buffer)) != 0) {}
if (report)
System.out.println((System.currentTimeMillis()-t) + " ms");
}
public static int readToArray(InputStream is, byte[] buffer) throws IOException
{
int index = 0;
while (index != buffer.length)
{
int read = is.read(buffer, index, buffer.length - index);
if (read == -1)
break;
index += read;
}
return index;
}
}
Run Code Online (Sandbox Code Playgroud)
输出
422 ms
717 ms
422 ms
718 ms
Run Code Online (Sandbox Code Playgroud)
请注意,这是对已发布问题的重新定义.另一方受到无关讨论的污染.我会将另一个标记为删除.
编辑:重复,真的吗?我当然可以做一些更好的代码,以证明我的观点,但是这并没有回答我的问题
Edit2:我在
Win7/JRE 1.8.0_25 上运行了5 KB到1000 KB之间的每个缓冲区的测试,并且错误的性能从精确的508 KB和随后的所有内容开始.对不起的图表军团很抱歉,x是缓冲区大小,y是毫秒

TL; DR性能下降是由内存分配引起的,而不是由文件读取问题引起的.
典型的基准测试问题:您对一件事进行基准测试,但实际上衡量另一件事
首先,当我使用重写了代码示例RandomAccessFile,FileChannel并且ByteBuffer.allocateDirect,门槛已经消失了.对于128K和1M缓冲区,文件读取性能大致相同.
与直接ByteBuffer不同,I/O FileInputStream.read无法将数据直接加载到Java字节数组中.它需要首先将数据放入某个本机缓冲区,然后使用JNI SetByteArrayRegion函数将其复制到Java .
所以我们必须看一下本机的实现FileInputStream.read.它归结为io_util.c中的以下代码:
if (len == 0) {
return 0;
} else if (len > BUF_SIZE) {
buf = malloc(len);
if (buf == NULL) {
JNU_ThrowOutOfMemoryError(env, NULL);
return 0;
}
} else {
buf = stackBuf;
}
Run Code Online (Sandbox Code Playgroud)
这里BUF_SIZE == 8192.如果缓冲区大于此保留堆栈区域,则分配临时缓冲区malloc.在Windows malloc上通常通过HeapAlloc WINAPI调用实现.
接下来,我在没有文件I/O的情况下单独测量了HeapAlloc+ HeapFree调用的性能.结果很有趣:
128K: 5 ?s
256K: 10 ?s
384K: 15 ?s
512K: 20 ?s
640K: 25 ?s
768K: 29 ?s
896K: 33 ?s
1024K: 316 ?s <-- almost 10x leap
1152K: 356 ?s
1280K: 399 ?s
1408K: 436 ?s
1536K: 474 ?s
1664K: 511 ?s
1792K: 553 ?s
1920K: 592 ?s
2048K: 628 ?s
Run Code Online (Sandbox Code Playgroud)
如您所见,OS内存分配的性能在1MB边界处急剧变化.这可以通过用于小块和大块的不同分配算法来解释.
UPDATE
HeapCreate的文档确认了关于大于1MB的块的特定分配策略的想法(请参阅dwMaximumSize描述).
此外,可以从堆分配的最大内存块对于32位进程略小于512 KB,对于64位进程略小于1,024 KB.
...
分配大于固定大小堆限制的内存块的请求不会自动失败; 相反,系统调用VirtualAlloc函数来获取大块所需的内存.
| 归档时间: |
|
| 查看次数: |
1405 次 |
| 最近记录: |