none
Утечка памяти при отправке больших файлов через HttpWebResponse C#! RRS feed

  • Общие обсуждения

  • Отправляю

    private Task<string> SendAsync(string SendFiles)
            {
                return Task.Run(() =>
                {
                    FileInfo fileInfo = new FileInfo(SendFiles);
                    using (var file = new FileStream(SendFiles, FileMode.Open))
                    {
                        byte[] data = new byte[file.Length];
                        file.Read(data, 0, data.Length);
                        file.Close();

                        Dictionary<string, object> postParameters = new Dictionary<string, object>
                        {
                            { "file", new Upload.FileParameter(data, fileInfo.FullName, "application/xml") },
                            { "sendUser",  Settings.Default.User},
                            { "project", Settings.Default.CurrentProject },
                            { "touser", Settings.Default.ToUser }
                        };
                        string postURL = string.Format("{0}/FileManager/upload.php", Settings.Default.WebResource);
                        using (var response = Upload.MultipartFormDataPost(postURL, postParameters))
                        {
                            response.Close();
                            return fileInfo.Name;
                        }
                    }
                });
            }

    Сам класс Upload

    public class Upload
        {
            private static readonly Encoding encoding = Encoding.UTF8;
            public static HttpWebResponse MultipartFormDataPost(string postUrl, Dictionary<string, object> postParameters)
            {
                string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid());
                string contentType = "multipart/form-data; boundary=" + formDataBoundary;

                byte[] formData = GetMultipartFormData(postParameters, formDataBoundary);

                return PostForm(postUrl, contentType, formData);
            }
            private static HttpWebResponse PostForm(string postUrl, string contentType, byte[] formData)
            {
                HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;

                if (request == null)
                {
                    throw new NullReferenceException("request is not a http request");
                }
                request.Method = "POST";
                request.ContentType = contentType;
                request.CookieContainer = new CookieContainer();
                request.ContentLength = formData.Length;

                using (Stream requestStream = request.GetRequestStream())
                {
                    requestStream.Write(formData, 0, formData.Length);
                    requestStream.Close();
                }
                return request.GetResponse() as HttpWebResponse;
            }

            private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary)
            {
                Stream formDataStream = new MemoryStream();
                bool needsCLRF = false;

                foreach (var param in postParameters)
                {
                    if (needsCLRF)
                        formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n"));

                    needsCLRF = true;

                    if (param.Value is FileParameter)
                    {
                        FileParameter fileToUpload = (FileParameter)param.Value;
                        string header = string.Format("--{0}\r\nContent-Dis-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n",
                            boundary,
                            param.Key,
                            fileToUpload.FileName ?? param.Key,
                            fileToUpload.ContentType ?? "application/octet-stream");

                        formDataStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header));
                        formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length);
                    }
                    else
                    {
                        string postData = string.Format("--{0}\r\nContent-Dis-data; name=\"{1}\"\r\n\r\n{2}",
                            boundary,
                            param.Key,
                            param.Value);
                        formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData));
                    }
                }
                string footer = "\r\n--" + boundary + "--\r\n";
                formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer));
                formDataStream.Position = 0;
                byte[] formData = new byte[formDataStream.Length];
                formDataStream.Read(formData, 0, formData.Length);
                formDataStream.Close();

                return formData;
            }

            public class FileParameter
            {
                public byte[] File { get; set; }
                public string FileName { get; set; }
                public string ContentType { get; set; }
                public FileParameter(byte[] file) : this(file, null) { }
                public FileParameter(byte[] file, string filename) : this(file, filename, null) { }
                public FileParameter(byte[] file, string filename, string contenttype)
                {
                    File = file;
                    FileName = filename;
                    ContentType = contenttype;
                }
            }
        }

    Как оптимизировать код чтоб была возможность отправлять файлы большего объема?

    При отправки файла размером 237mb, съедает более 700 метров памяти и в итоге на сервер нечего не загружается.

    При отправки файлов до 150mb, все отправляется хорошо не считая того что потребляет памяти на отправку в 2 раза выше чем весит сам файл. 

    И в общем то еще вчера при первых тестах удавалось отправлять файлы размером до 550mb, уже сегодня более 200 метров не отправляется в чем причина, понять не могу так как код не менял. 



    • Изменено MacroMax 27 декабря 2017 г. 4:38
    • Изменен тип MacroMax 27 декабря 2017 г. 4:38
    27 декабря 2017 г. 4:35

Все ответы

  • Нехватка памяти =/= утечка памяти. Скорее всего, система просто не может выделить непрерывный блок памяти необходимой длины (даже если в сумме свободной памяти достаточно). Вместо считывания всего массива из formDataStream целиком, нужно считывать данные отдельными порциями, и соответственно в RequestStream тоже писать отдельными порциями.
    27 декабря 2017 г. 5:33
  • Нехватка памяти =/= утечка памяти. Скорее всего, система просто не может выделить непрерывный блок памяти необходимой длины (даже если в сумме свободной памяти достаточно). Вместо считывания всего массива из formDataStream целиком, нужно считывать данные отдельными порциями, и соответственно в RequestStream тоже писать отдельными порциями.
    Где можно посмотреть примеры? И не будет ли проблем у удаленного сервера с получением данных пакетами ?
    27 декабря 2017 г. 6:14
  • Ой, не увидел, что formDataStream это MemoryStream. От него надо будет избавится и работать напрямую с FileStream. Что-то вроде 

    fileStream.CopyTo(RequestStream);

    Посмотрите, здесь вроде что-то есть.

    Проблем не будет, так как в Http все и так отправляется пакетами.


    27 декабря 2017 г. 7:00