我有一个用C#编写的TCP服务器来处理发送给它的POST数据。目前它工作正常,除非向其发送大量数据(即大于1GB)然后它耗尽内存(我将它作为字节数组存储在内存中(具有List DTO的中介))。对于大文件,我现在流式传输到磁盘,然后传递文件名,意图从磁盘流式传输。
目前我的所有例程都是为了预期字节数组而编写的,事后看来,它们有点短视。如果我只是将bytearray转换为内存流,它会使内存使用量增加一倍吗?我想重写我的代码来处理内存流将允许我在从磁盘读取流时重新使用它吗?
很抱歉这些愚蠢的问题,我不知道c#何时获取数据副本或何时需要参考。
答案 0 :(得分:1)
如果您将byte[]
传递给MemoryStream
,那么它最初会复制数据(在构造函数中),但只要您释放byte[]
就可以进行垃圾回收。本质上没有“加倍”(特别是如果您可以正确设置大小,并直接写入Stream
而不是byte[]
)。
我完全会说切换到Stream
(但仅在API中使用Stream
- 没有特定的moer;您的消费代码不需要知道哪种类型) 。最重要的是,您可以选择使用NetworkStream
(直接从套接字读取)或FileStream
(如果要缓冲到磁盘),或MemoryStream
如果要缓冲-处理。您还需要确保通过基于流的代码读取该数据量。迭代器块(yield return
)在这里非常有用,LINQ Enumerable
方法(除OrderBy
,GroupBy
等之外的缓冲区除外)。
传递byte[]
或传递Stream
都不会导致复制任何内容,因为它们是引用类型 - 唯一复制的是引用(4或8个字节,具体取决于x86 / x64) )。
答案 1 :(得分:0)
MemoryStream只是一个字节数组的流包装器,因此使用它不会获得任何东西。
您需要做什么(至少对于大型文件)是打开FileStream并将数据转储到其中。在较低级别,您必须从连接中读取X字节,然后立即将其写入文件流。这样你就不会将完整的演出拉入内存,但一次只能输入几个字节。
这是否容易实现取决于您的TCP服务器的编码方式。
答案 2 :(得分:0)
由于字节是值类型,如果将其传递给不带ref关键字的函数,则每次都要处理一个副本。如果使用ref关键字传递它,它将引用原始字节数组。
内存流是一种引用类型,因此它不会复制数据,但是你传递了对该数据的引用,因此在使用它时你的内存使用量不会加倍。