2010-10-14 41 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

首先,您應該對所有實現IDisposable的類的實例(如Stream)使用using語句,以確保即使發生異常時它們也會關閉並清理乾淨。 – sloth 2010-10-14 14:23:01

回答

1

檢查你在這裏使用的所有對象,以確保它們不需要是Dispose-d(即它們是否實現了IDisposable?)。否則,每次執行代碼時,都會遇到與每個對象關聯的非託管資源泄漏。

您可以使用using以異常安全的方式整理確保爲此類對象調用Dispose()。舉例

- 而不是:

SqlCommand cmd = new SqlCommand(); 

使用這種包裝使用cmd

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

請注意,您EventLogger類也可能需要實現IDisposable如果它是一個封裝了自定義類的代碼通過(例如)FileEventLog的非託管資源。

您可以在MSDN文檔中檢查您在程序中的其他內置類中使用的其他內置類。

+0

感謝您的回答。我會執行你的建議。但是那種不好的編程會在5分鐘內導致200 MB額外的內存使用嗎?應用程序在啓動時使用25 MB內存。 – Olcay 2010-10-14 14:32:10

+0

額外的內存使用並非總是由於泄漏 - CLR使用託管堆和垃圾收集意味着您無法直接將進程大小與實際應用程序內存相關聯。我會試試看看會發生什麼。如果你需要在你的進程中使用詳細的內存使用信息,你將不得不使用一個CLR分析器,它允許跟蹤「實時」對象實例。 – 2010-10-14 14:38:13