1

我有一个用 C# 编写的 TCP 服务器来处理发送给它的 POST 数据。目前它工作正常,除非大量数据(即大于 1GB)被发送到它然后它耗尽内存(我将它全部存储在内存中作为字节数组(以 List DTO 为中介))。对于大文件,我现在流式传输到磁盘,然后传递文件名,目的是从磁盘流式传输。

目前我所有的例程都是为了期待字节数组而编写的,事后看来,这有点短视。如果我只是将字节数组转换为内存流,它会使内存使用量翻倍吗?我认为重写我的代码以处理内存流将允许我在从磁盘读取流时重新使用它?

很抱歉这些愚蠢的问题,我不确定 c# 何时获取数据副本或何时获取引用。

4

3 回答 3

1

如果您将 a 传递给byte[]a MemoryStream,那么它最初会复制数据(在构造函数中),但只要您释放它,byte[]它就可以被垃圾收集。本质上没有“加倍”(特别是如果您可以正确设置大小开始,并直接写入Stream而不是byte[])。

我会完全说切换到Stream(但在 API 中使用Stream- 没有更具体的;您的消费代码不需要知道哪种类型)。最重要的是,您可以选择使用NetworkStream(直接从套接字读取)或FileStream(如果要缓冲到磁盘),或者MemoryStream如果要在进程中缓冲。您还需要确保通过基于流的代码读取大量数据。迭代器块 ( yield return) 在这里非常有用,LINQEnumerable方法也可以(除了OrderBy,GroupBy等,哪个缓冲区)。

传递 abyte[]或传递 a都不会Stream导致任何内容被复制,因为它们是引用类型 - 唯一复制的是引用(4 或 8 个字节,取决于 x86/x64)。

于 2010-01-05T12:21:39.310 回答
0

MemoryStream 只是一个字节数组的流包装器,因此您不会通过使用它获得任何东西。

您需要做的(至少对于大文件)是打开一个 FileStream 并在其中转储您的数据。在较低级别,您必须从连接中读取 X 字节,然后立即将其写入文件流。这样,您就不会将完整的演出拉入内存,而一次只能提取几个字节。

这是否容易做到取决于你的 TCP 服务器是如何编码的。

于 2010-01-05T12:20:17.933 回答
0

由于字节是一种值类型,如果你将它传递给一个没有 ref 关键字的函数,你每次都会处理一个副本。如果您使用 ref 关键字传递它,它将引用原始字节数组。

内存流是一种引用类型,因此它不会复制数据,但您传递的是对该数据的引用,因此使用它时您的内存使用量不会翻倍。

于 2010-01-05T12:20:57.633 回答