2010-01-05 62 views
1

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

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

对不起,愚蠢的问题,我不知道什么时候c#获取数据的副本或何时需要引用。

回答

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)。

0

MemoryStream只是一个字节数组的流封装,所以你不会因为使用它而获得任何东西。

你需要做什么(对于大文件至少)是打开一个FileStream并在其中转储数据。在较低的级别,您必须从连接中读取X个字节,然后立即将其写入文件流。这样你就不会将内存中的内容全部转换成内存,而只需要一次处理几个字节。

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

0

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

memorystream是一个引用类型,所以它不会复制数据,但是您传递的是对该数据的引用,所以在使用该引用时内存使用量不会增加一倍。

+0

OP询问关于传递一个字节[],据我所知,所有数组都是引用类型。它可能会保存值类型(在这个例子中是字节),但是数组本身是一个引用类型。 – trickdev 2011-11-21 11:43:32