2012-04-13 68 views
3

我使用:的Java IO性能问题

PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("test.txt"),1024*1024*500)) 

写一个大文件(大约2GB)。写入需要26秒。但是,当我用10/20替换500时,需要19秒。

here,我了解的是缓冲给出更好的性能。如果是这样,那么为什么会发生?我通过每次运行5次来检查它,所以系统/ IO负载不是问题。

+1

可能的重复[如何确定使用FileInputStream时的理想缓冲区大小?](http://stackoverflow.com/ question/236861/how-do-you-determine-the-ideal-buffer-size-when-file-fileinputstream) – 2012-04-13 15:24:05

+0

非常相似的问题,非常相似的答案:http://stackoverflow.com/a/237495/1315900 – 2012-04-13 15:19:50

回答

2

正如我在前面的问题中所说的那样,存在一个最佳缓冲区大小(通常大约为32 KB),并且当您使缓冲区大于此值时,速度会变慢而不会更快。默认缓冲区大小为8 KB。

顺便说一句:你的L2/L3 CPU缓存有多大? (我怀疑大约10 MB)您的主L1缓存大约是32 KB?

通过使用适合最快缓存的缓冲区,可以使用最快的内存。通过使用仅适用于主内存的缓冲区,您使用最慢的内存(速度慢10倍)


回答您的问题。

我所做的是假设ISO-8859-1编码,即(byte) ch,并一次写入一个字节到一个ByteBuffer,可能是内存映射。

我有写/读longdouble从ByteBuffer方法没有创建任何垃圾。

https://github.com/peter-lawrey/Java-Chronicle/blob/master/src/main/java/vanilla/java/chronicle/impl/AbstractExcerpt.java

使用这种方法,您可以登录每秒约5万线到磁盘。

+0

另一个很好的答案。谢谢。你可以通知PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(“compresedchr1.txt”),32KB)); out.print(char) - 哪个nio函数替代了这个?那个更快吗?或者任何其他方式来写字符? – Arpssss 2012-04-13 15:23:57

+0

看我的编辑... – 2012-04-13 15:35:04

1

1024*1024*500是500兆字节,给予或采取smidgen。你基本上是迫使JVM分配500MB的连续内存块,JVM可能需要做一个GC循环。

+0

不,我有16 GB的内存。 JVM分配5/6 GB。我认为没有GC循环。 – Arpssss 2012-04-13 15:25:33

1

非常大的缓冲区(500 MB)也不好,因为操作系统对于那个巨大的字节缓冲区的内存管理会更困难。

将它与在你的房子中移动一张桌子比较,而不是移动一个框。但是如果你的盒子变得太小,你将不得不多次去。

不要忘记分配内存是O(n)操作。

+0

谢谢。我知道了。 – Arpssss 2012-04-13 15:26:53

2

缓冲区过大会降低性能。坚持到32-64 kb IMO

1

首先你真的不需要一个大的缓冲区。通常64K甚至低至8K就足以获得下降IO性能。任何更大的,你只是浪费内存和CPU,因为当你获得越来越大的缓冲区时,它会在IO层花费更多时间写入大量数据。因此,在等待IO和写入内存之间进行折衷(如果您了解微积分,则为最小 - 最大值)。由于IO设备具有内部固定大小的缓冲区,因此无法将巨大缓冲区推送到IO设备。重点是尽可能地尝试和匹配它,但意识到这样做相对不可能,因为你不知道其他处理正在做什么。最好的办法是尝试低8K-16K,运行它,测量它。加倍缓冲区32K等,运行它,测量它。如果你获得了速度提升,那就再做一次。一旦你停止获得速度提升除以2,并停止。

因此,如果您在26s中写入2GB数据,那么吞吐量为76MB/S或650Mbit/s。您可以通过将缓冲区大小降低到合理值来改善它。

+0

谢谢。我知道了。 – Arpssss 2012-04-13 15:28:08

1

缓冲你的I/O通过减少系统调用的次数来提高性能。但系统调用并不是那么昂贵(可能是一毫秒左右),而过大的缓冲区可能会在其他方面造成问题。例如:

  • 500 MB缓冲区使用大量内存,并可能增加GC开销或增加系统的寻呼负载。

  • 如果您在单次写入调用中写入500 MB字节,写入操作可能会使系统的缓冲区缓存饱和,并且压倒其在应用程序级别与其他事物重叠写入磁盘的能力。

只是尝试使用(显着)较小的缓冲区。 (我个人不会使用大于8kb的缓冲区,而不进行特定于应用程序的调整。)