HttpWebClient имеет высокое использование памяти в MonoTouch - PullRequest
0 голосов
/ 22 октября 2011

У меня есть универсальное приложение iOS на основе MonoTouch.Он использует сервисы REST для звонков для получения данных.Я использую класс HttpWebRequest для создания и выполнения своих вызовов.Все прекрасно работает, за исключением того, что кажется, что он держит память.Я использую весь код, чтобы ограничить сферу действия.Я избегал анонимных делегатов, а также слышал, что они могут быть проблемой.У меня есть вспомогательный класс, который создает мой вызов к моей службе REST.Когда я делаю звонки, кажется, что я просто держу память от своих звонков.Мне любопытно, сталкивался ли кто-нибудь с подобными проблемами с HttpWebClient и что с этим делать.В настоящее время я смотрю, могу ли я сделать вызов с помощью nsMutableRequest и просто избежать HttpWebClient, но я пытаюсь заставить его работать с аутентификацией NTLM.Любой совет приветствуется.

protected T IntegrationCall<T,I>(string methodName, I input) {
HttpWebRequest invokeRequest = BuildWebRequest<I>(GetMethodURL(methodName),"POST",input, true);
WebResponse response = invokeRequest.GetResponse();

T result = DeserializeResponseObject<T>((HttpWebResponse)response);
invokeRequest = null;
response = null;
return result;
}

protected HttpWebRequest BuildWebRequest<T>(string url, string method, T requestObject, bool IncludeCredentials)
{
ServicePointManager.ServerCertificateValidationCallback = Validator;

        var invokeRequest = WebRequest.Create(url) as HttpWebRequest;
        if (invokeRequest == null)
            return null;

        if (IncludeCredentials)
        {
            invokeRequest.Credentials = CommonData.IntegrationCredentials;
        }

        if( !string.IsNullOrEmpty(method) )
            invokeRequest.Method = method;
        else
            invokeRequest.Method = "POST";
        invokeRequest.ContentType = "text/xml";
        invokeRequest.Timeout = 40000;

        using( Stream requestObjectStream = new MemoryStream() )
        {
            DataContractSerializer serializedObject = new DataContractSerializer(typeof(T));
            serializedObject.WriteObject(requestObjectStream, requestObject);

            requestObjectStream.Position = 0;
            using(StreamReader reader = new StreamReader(requestObjectStream))
            {
                string strTempRequestObject = reader.ReadToEnd();

                //byte[] requestBodyBytes = Encoding.UTF8.GetBytes(strTempRequestObject);
                Encoding enc = new UTF8Encoding(false);
                byte[] requestBodyBytes = enc.GetBytes(strTempRequestObject);

                invokeRequest.ContentLength = requestBodyBytes.Length;

                using (Stream postStream = invokeRequest.GetRequestStream())
                {
                    postStream.Write(requestBodyBytes, 0, requestBodyBytes.Length);
                }
            }
        }

        return invokeRequest;
    }

1 Ответ

1 голос
/ 23 октября 2011

Использование с использованием - это правильно, но ваш код, похоже, дублирует один и тот же контент несколько раз (чего не следует делать).

requestObjectStream превращается вstring, который затем превращается в byte[] перед записью в другой поток.И это без с учетом того, что дополнительный код (например, ReadToEnd и UTF8Encoding.GetBytes) может распределить самостоятельно (например, как больше строк , байт [] ...).

Так что, если то, что вы сериализуете, велико, то вы будете использовать много дополнительной памяти (даром).Это даже немного хуже для string и byte[], так как вы не можете утилизировать их вручную (GC примет решение, когда, затрудняя измерение).

Я бы попробовал (но не сделал ;-) что-то вроде:

    ...

    using (Stream requestObjectStream = new MemoryStream ()) {
        DataContractSerializer serializedObject = new DataContractSerializer(typeof(T));
        serializedObject.WriteObject(requestObjectStream, requestObject);
        requestObjectStream.Position = 0;

        invokeRequest.ContentLength = requestObjectStream.Length;
        using (Stream postStream = invokeRequest.GetRequestStream())
           requestObjectStream.CopyTo (postStream);
    } 

    ...

Это позволило бы MemoryStream скопировать себя в поток запросов.Альтернативой является вызов ToArray для MemoryStream (но это еще одна копия сериализованного объекта, которую GC должен будет отследить и освободить).

...