Преобразование больших строк в UTF-8 - PullRequest
3 голосов
/ 28 января 2012

У меня есть служба WCF4 REST, которая запрашивает базу данных и возвращает JSON. Некоторые пользователи хотят делать очень большие запросы, хотя у меня возникают трудности с возвратом строки. Например, мне нужно вернуть 500-метровую строку JSON (все данные - текст ASCII), хотя, когда я пытаюсь преобразовать строку из нативного UTF-16 .NET, я нажимаю исключение OutOfMemoryException. Вот небольшой пример того, что я делаю.

[WebInvoke(UriTemplate="/RunQuery", ResponseFormat=WebMessageFormat.Json)]
public Stream RunQuery() {
    // Perform query and return serialized json string (~500 million ASCII characters)
    string json = DoQuery(HttpContext.Current.Request.Form);
    // Set output charset
    WebOperationContext.Current.OutgoingResponse.ContentType = "application/json; charset=utf-8";
    // Convert UTF-16 string to UTF-8 (OutOfMemoryException)
    byte jsonBytes[] = System.Text.Encoding.UTF8.GetBytes(json)
    // Send UTF-8 string, without BOM
    return new MemoryStream(jsonBytes);
}

Это работает только если я держу JSON ниже 200M или около того. Пока он работает, я вижу, что использование памяти процессом IIS возрастает, а затем взрывается до 2.8G, и в этот момент он умирает. Трассировка стека сообщает об этом в System.String.ToCharArray. Я пробовал варианты разбиения строки на части для создания байтового массива, но, похоже, ничего не работает. Любая идея, как я могу отправить эти данные без взрыва?

Ответы [ 2 ]

0 голосов
/ 28 января 2012

Если вам нужно вернуть поток - используйте файловый поток или хотя бы предварительно выделите пространство MemoryStream.

Если вам нужно придерживаться строки 500 МБ:

  • использовать 64-битную машину и 64-битный процесс. Маловероятно, что процесс x86 сможет успешно выделить 2 куска памяти такого размера. Обратите внимание, что даже если вы используете 64-битный процесс, CLR имеет ограничение на «выделение одного блока» размером около 2 ГБ, поэтому строки размером 1 ГБ вряд ли поместятся в памяти. Так что в какой-то момент около 500 Мб - переключение на 64-битную 1 Гб больше не поможет.

  • используют Writers - они могут легко (т.е. http://msdn.microsoft.com/en-us/library/3aadshsx.aspx) кодировать непосредственно в вывод при записи в него вашего JSON. В качестве дополнительной рекомендации - даже не создавайте строку JSON для начала, записывайте вывод в Писатель вместо.

  • Если вы знаете, что ваша строка - только ASCII - читы, написав для потокового воспроизведения каждого символа в виде байта.

0 голосов
/ 28 января 2012

Вы можете исправить это, написав собственную реализацию stream , которая на лету преобразует ввод в utf8.

Вы должны быть в состоянии сделать это, извлекая части входной строки, преобразовывая их в utf 8 блок за блоком.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...