分配字节数组是否对性能至关重要?

时间:2014-04-05 19:21:54

标签: c# .net performance generic-handler

在我的小文件传输网站(this one,运行.NET 4.5.1)中,我按照Microsoft知识库文章812406将以前上传的文件从服务器发送到浏览器。

进行性能优化我很惊讶发现这行

var buffer = new byte[10000];

需要相当长的一段时间(我使用红门' s ANTS Performance Profiler)。缓冲区仅在每个完整下载/客户端分配一次。

我的问题:

  • 以这种方式分配缓冲区这个大小是不错的做法?
  • 分配~10k缓冲区的其他选择吗?

更新1:

感谢您的评论我已经看到内存也在循环内部分配。

尽管如此,ANTS Profiler只标记循环外 的分配需要花费那么多时间,但老实说我还不明白。我已经删除了循环中的(无意义的)分配。

更新2:

实施了建议的BufferManager并将缓冲区大小从10k减少到4096(以防万一......),我的网站运行起来非常顺利。

4 个答案:

答案 0 :(得分:4)

在.NET中创建对象通常非常快,但由于此数组对象具有较大的大小,因此清除其所有字节需要很长时间。 C#始终将所有字节设置为0,从而在创建对象时将所有字段设置为其默认值。 (构造函数和字段初始值设定项当然可以在类和结构中分配不同的值。)

example given by Microsoft中,缓冲区在循环之前分配,永远不会改变其大小。此外,写入输出流只会写入所需的字节。

// Gets the exact number of bytes read
length = iStream.Read(buffer, 0, 10000);

// Writes only 'length' bytes to the output
Response.OutputStream.Write(buffer, 0, length);

因此,无需通过在每次循环迭代中分配新缓冲区来“清除”缓冲区。脏的额外字节不会受到伤害。

解决方案:将行buffer= new Byte[10000];放入while循环!

答案 1 :(得分:3)

是。实际上,WCF uses a "buffer manager" to prevent this problem

我一直在开发network service,在分析过程中,我发现Byte[]缓冲区的分配造成了瓶颈。不仅在分配期间,而且处理器在GC中浪费的时间也非常高。重用这些缓冲区并避免分配的改进可以带来非常大的性能提升。

您可以使用BufferManager类来避免编写自己的缓冲区管理策略。

答案 2 :(得分:1)

调用这样的构造函数,尤其是使用如此大的缓冲区,肯定会花费大量的CPU时间。当然,你的问题的答案将基于意见,但这是我的:

  1. 分配该大小的缓冲区没有任何问题。 10K在现代系统上并没有那么多的记忆。当然,在任何类型的循环中这样做都会很快耗尽CPU时间。

  2. 如果可以,请尽量避免为每次使用重建缓冲区。使用先前定义的缓冲区可避免每次需要时重新分配内存。当然,如果这是线程化的(多个连接),每个连接/线程都需要自己的缓冲区,但至少每个连接有一个分配,而不是每个" chunk的新缓冲区"如链接示例中所示的流数据。

答案 3 :(得分:1)

如果您有文件传输任务,建议使用Microsoft.IO.RecyclableMemoryStream

它具有RecyclableMemoryStreamManager类型,可以创建RecyclableMemoryStream(在内部重用字节)。

优点:

  • 它在内部重用字节数组。例如。如果您需要临时内存流,这些类将为您提供它,而无需进行额外的清理。
  • 它按块划分内部数组。

缺点:

  • 您应处置每个流(否则您的应用程序将使用大量内存)