TCP-сервер и MemoryStreams / ByteArrays - PullRequest
1 голос
/ 05 января 2010

У меня есть TCP-сервер, написанный на C #, который обрабатывает отправленные ему данные POST. В настоящее время он работает нормально, если на него не отправляется большой объем данных (то есть больше 1 ГБ), а затем ему не хватает памяти (я храню все это в памяти как массив байтов (с посредником List DTO)). Теперь для больших файлов я передаю их на диск, а затем передаю имя файла с намерением передать его с диска.

В настоящее время все мои подпрограммы написаны так, чтобы ожидать байтовых массивов, которые, оглядываясь назад, были немного близорукими. Если я просто преобразую байтовый массив в поток памяти, это удвоит использование памяти? Я думаю, что переписывание моего кода для работы с потоком памяти позволит мне использовать его повторно, когда я читаю поток с диска?

Извините за глупые вопросы, я никогда не уверен, когда c # берет копию данных или когда он берет ссылку.

Ответы [ 3 ]

1 голос
/ 05 января 2010

Если вы передадите byte[] в MemoryStream, то он будет первоначально копировать данные (в конструкторе), но до тех пор, пока вы освобождаете byte[], он может собирать мусор. По сути, нет «удвоения» (особенно, если вы можете правильно установить размер для начала и писать прямо в Stream, а не byte[]).

Я бы полностью сказал, переключитесь на Stream (но только использует Stream в API - ничего особенного; ваш потребительский код не должен знать, какой тип). Самое главное, вы можете выбрать NetworkStream (для чтения непосредственно из сокета) или FileStream (если вы хотите выполнить буферизацию на диск), или MemoryStream, если вы хотите буферизовать в процессе. Вам также необходимо убедиться, что вы читаете этот объем данных с помощью потокового кода. Блоки итераторов (yield return) могут быть очень полезны здесь, как и методы LINQ Enumerable (за исключением OrderBy, GroupBy и т. Д., Которые буферизуют).

Ни передача byte[], ни передача Stream не приводит к копированию чего-либо, так как они являются ссылочными типами - единственное, что копируется - это ссылка (4 или 8 байтов, в зависимости от x86 / x64).

0 голосов
/ 05 января 2010

Поскольку байт является типом значения, если вы передадите его функции без ключевого слова ref, вы будете иметь дело с копией каждый раз. Если вы передадите его с помощью ключевого слова ref, оно получит ссылку на исходный байтовый массив.

Поток памяти является ссылочным типом, поэтому он не будет копировать данные, но вы передаете ссылку на эти данные, поэтому использование вами памяти не увеличится вдвое.

0 голосов
/ 05 января 2010

MemoryStream - это просто обертка потока вокруг байтового массива, поэтому вы не получите ничего, используя его.

Что вам нужно сделать (по крайней мере, для больших файлов) - это открыть FileStream и сохранить в нем ваши данные. На более низком уровне вы должны прочитать X байтов из вашего соединения, а затем сразу же записать это в ваш файловый поток. Таким образом, вы не будете вставлять в память полный гигабайт, а только несколько байтов за раз.

Будет ли это легко сделать, зависит от того, как закодирован ваш TCP-сервер.

...