Загрузка по FTP - проблема утечки памяти - PullRequest
1 голос
/ 14 октября 2010

Я работаю над личным проектом, который загружает и скачивает большие файлы по протоколу FTP. Работает нормально, кроме утечки памяти, которую я недавно заметил. Я не знаю точно, в чем проблема. Это может быть утечка памяти или плохое программирование. Объем памяти, используемый этим приложением, увеличивается каждую секунду при загрузке. Вот код:

    Action action;
    int bufferSize = 16384;
    EventLogger elog = new EventLogger();
    string error = "";
    string filename = "";

    public Uploader(Action action)
    {
        this.action = action;
        filename = action.directory.Substring(action.directory.LastIndexOf('\\') + 1,
            action.directory.Length - action.directory.LastIndexOf('\\') - 1);
    }

    public bool startUpload()
    {   
        try
        {
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://*******");
            request.Method = WebRequestMethods.Ftp.ListDirectory;
            request.Credentials = new NetworkCredential("***", "***");

            FtpWebResponse response = (FtpWebResponse)request.GetResponse();

            Stream responseStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(responseStream);
            List<string> files = new List<string>();
            string[] filesArr = reader.ReadToEnd().Split('\n');
            reader.Close();
            response.Close();
            foreach (string file in filesArr)
                files.Add(file.Replace("\r", ""));
            if (files.IndexOf(filename) != -1)
            {
                request = (FtpWebRequest)WebRequest.Create("ftp://***/"+filename);
                request.Method = WebRequestMethods.Ftp.DeleteFile;
                request.Credentials = new NetworkCredential("***", "***");
                response = (FtpWebResponse)request.GetResponse();
                reader.Close();
                response.Close();
                if (response.StatusCode != FtpStatusCode.FileActionOK)
                {
                    return false;
                }
            }

            request = (FtpWebRequest)WebRequest.Create("ftp://***/"+filename);
            request.Method = WebRequestMethods.Ftp.UploadFile;
            request.KeepAlive = false;
            request.UseBinary = true;

            FileStream stream = File.OpenRead(action.directory);
            byte[] buffer = new byte[bufferSize];
            Stream reqStream = request.GetRequestStream();

            SqlCommand cmd = new SqlCommand();
            cmd.CommandText = "update DIRECT_UPLOAD set COMPLETED = @com, PROGRESS = @prog, SPEED = @speed where ID = @id";
            cmd.Parameters.AddWithValue("@id", action.id);
            cmd.Parameters.AddWithValue("@com", 0);
            cmd.Parameters.AddWithValue("@prog", 0);
            cmd.Parameters.AddWithValue("@speed", 0);


            long i = 0;
            int readed = 0;
            int total = 0;
            int speed = 0;
            DateTime last = DateTime.Now;
            int lastTotal = 0;
            while ((readed = stream.Read(buffer, 0, bufferSize)) > 0)
            {
                reqStream.Write(buffer, 0, readed);
                total += readed;
                if (i % 100 == 0)
                {
                    cmd.Parameters["@com"].Value = total;
                    cmd.Parameters["@prog"].Value = (int)(((double)total / action.size) * 100);
                    int tot = 0;
                    tot = total - lastTotal;
                    int time = Convert.ToInt32((DateTime.Now - last).TotalMilliseconds);
                    speed = (int)(((double)1000.0 / time) * tot);
                    cmd.Parameters["@speed"].Value = speed;
                    if ((error = SqlProcess.sqlNonQuery(cmd)) != "")
                        throw new Exception(error);
                    last = DateTime.Now;
                    lastTotal = total;
                }

                Application.DoEvents();
                i++;
            }

            cmd.Parameters["@com"].Value = total;
            cmd.Parameters["@prog"].Value = 100;
            cmd.Parameters["@speed"].Value = 0;
            if ((error = SqlProcess.sqlNonQuery(cmd)) != "")
                throw new Exception(error);

            reqStream.Close();
            stream.Close();
        }
        catch (Exception ex)
        {
            elog.write(ex);
            return false;
        }
        return true;
    }

Спасибо.

1 Ответ

1 голос
/ 14 октября 2010

Проверьте все объекты, которые вы используете здесь, чтобы убедиться, что они не должны быть Dispose -d (т.е. они реализуют IDisposable?). В противном случае вы будете испытывать утечку неуправляемых ресурсов, связанных с каждым из этих объектов, каждый раз, когда выполняется этот код.

Вы можете использовать using, чтобы аккуратно убедиться, что Dispose() вызывается для таких объектов безопасным для исключения способом.

Пример - вместо:

SqlCommand cmd = new SqlCommand();

используйте это, чтобы обернуть код, который использует cmd

using (SqlCommand cmd = new SqlCommand())
{
}

Обратите внимание, что вашему классу EventLogger может также потребоваться реализация IDisposable, если это пользовательский класс, который оборачивает неуправляемые ресурсы через (например) File или EventLog.

Вы можете проверить другие встроенные классы, которые вы используете здесь и в других местах вашей программы, в документах MSDN.

...