2010-10-14 3 views
1

Я работаю над личным проектом, который загружает и загружает большие файлы с использованием протокола FTP. Он отлично работает, за исключением утечки памяти, которую я недавно заметил. Я точно не знаю, в чем проблема. Это может быть утечка памяти или плохое программирование. Объем памяти, используемый этим приложением, увеличивается каждую секунду при загрузке. Вот код: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; 
    } 

спасибо.

+0

Прежде всего, вы должны использовать инструкцию using для всех экземпляров классов, которые реализуют IDisposable (например, Stream), чтобы быть уверенными, что они закрываются и очищаются даже при возникновении исключения. – sloth

ответ

1

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

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

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

SqlCommand cmd = new SqlCommand(); 

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

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

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

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

+0

Спасибо за ваш ответ. Я буду выполнять ваши предложения. Но является ли такое плохое программирование причиной использования дополнительной памяти в 200 МБ за 5 минут? При запуске приложение использует память 25 МБ. – Olcay

+0

Использование дополнительной памяти не всегда происходит из-за утечек - использование управляемой кучи и коллекции мусора с помощью CLR означает, что вы не можете напрямую соотнести размер процесса с фактическим использованием памяти приложения. Я попробую это и посмотрю, что произойдет. Если вам нужна подробная информация об использовании памяти в вашем процессе, вам придется использовать профилировщик CLR, который позволяет отслеживать «живые» экземпляры объектов. –

Смежные вопросы