2010-05-24 12 views
5

Czy ktoś może podać, czy istnieją ewentualne wycieki pamięci w następującym kodzie. Próbowałem z .NET Memory Profiler i napisałem "CreateEncryptor", a niektóre inne funkcje pozostawiły niezarządzane wycieki pamięci, co potwierdziłem za pomocą monitorów wydajności.W obliczu wycieków pamięci w metodzie szyfrowania AES

ale są już utylizowane, jasne, bliskie połączenia są umieszczane w miarę możliwości, poinformuj mnie odpowiednio. to było pilne.

public static string Encrypt(string plainText, string key) 
    { 
     //Set up the encryption objects 
     byte[] encryptedBytes = null; 
     using (AesCryptoServiceProvider acsp = GetProvider(Encoding.UTF8.GetBytes(key))) 
     { 
      byte[] sourceBytes = Encoding.UTF8.GetBytes(plainText); 
      using (ICryptoTransform ictE = acsp.CreateEncryptor()) 
      { 
       //Set up stream to contain the encryption 
       using (MemoryStream msS = new MemoryStream()) 
       { 
        //Perform the encrpytion, storing output into the stream 
        using (CryptoStream csS = new CryptoStream(msS, ictE, CryptoStreamMode.Write)) 
        { 
         csS.Write(sourceBytes, 0, sourceBytes.Length); 
         csS.FlushFinalBlock(); 

         //sourceBytes are now encrypted as an array of secure bytes 
         encryptedBytes = msS.ToArray(); //.ToArray() is important, don't mess with the buffer 

         csS.Close(); 
        } 

        msS.Close(); 
       } 
      } 

      acsp.Clear(); 
     } 

     //return the encrypted bytes as a BASE64 encoded string 
     return Convert.ToBase64String(encryptedBytes); 
    } 
    private static AesCryptoServiceProvider GetProvider(byte[] key) 
    { 
     AesCryptoServiceProvider result = new AesCryptoServiceProvider(); 
     result.BlockSize = 128; 
     result.KeySize = 256; 
     result.Mode = CipherMode.CBC; 
     result.Padding = PaddingMode.PKCS7; 

     result.GenerateIV(); 
     result.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 

     byte[] RealKey = GetKey(key, result); 
     result.Key = RealKey; 
     // result.IV = RealKey; 
     return result; 
    } 

    private static byte[] GetKey(byte[] suggestedKey, SymmetricAlgorithm p) 
    { 
     byte[] kRaw = suggestedKey; 
     List<byte> kList = new List<byte>(); 

     for (int i = 0; i < p.LegalKeySizes[0].MaxSize; i += 8) 
     { 
      kList.Add(kRaw[(i/8) % kRaw.Length]); 
     } 
     byte[] k = kList.ToArray(); 
     return k; 
    } 
+0

mi oczy na każde wezwanie nie ma specyficzny scenariusz zadzwoń funkcję szyfrowania wychodził około 30-40MB nieszczelności w 100K połączeń –

+0

Jeśli profiler mówi występuje przeciek pamięci w CreateEncryptor, dlaczego uważasz, że występuje w kodzie opublikowany? – dtb

+0

Ponieważ może być konieczne wyczyszczenie czegoś innego. –

Odpowiedz

7

Aktualizacja: Po jakimś dochodzeniu Zalogowałem to jako błąd na Microsoft connect. Potwierdzili błąd i utworzyli hotfix. (Oczywiście, jest to poprawka więc zastosować zwykłe zastrzeżenia. Jeśli możesz, uaktualnienie do .net 4.0 będzie prawdopodobnie preferowanym rozwiązaniem)


Wydaje się, że ten kod nieszczelności w .NET 3.5, ale to działa dobrze w .net 4.0.

Zacząłem w .net 4.0 i skopiowałem twój kod do szybkiej aplikacji testowej i nazwał to 1,000,000 razy, a zużycie pamięci pozostało stałe na poziomie 22,4mb przez cały czas. Śledziłem także rozmiary sterty GC i liczby zliczeń, a wszystkie pozostały niezmienione. O ile mogę powiedzieć, że kod nie wycieka.

Potem przebudowałem aplikację pod .net 3.5 i ponownie uruchomiłem test, a otrzymałem dokładny wyciek, który opisujesz. Zaczęło się od około 24 MB, a do czasu, gdy wykonano 100 000 połączeń, wykorzystanie pamięci podwoiło się do ponad 50 MB. Co ciekawe, wydawało się, że rośnie hałas Gen2, co sugeruje, że jest to wyciek pamięci zarządzanej, a nie niezarządzane uchwyty/pamięć.

Jeśli to możliwe, sugeruję spróbować przełączyć się na .net 4.0.

mój pełny kod:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Security.Cryptography; 
using System.IO; 

namespace ConsoleApplication5 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      String encryptedString; 


      for (int j = 0; j < 1000; j++) 
      { 
       for (int i = 0; i < 1000; i++) 
       { 
        encryptedString = Encrypt(String.Format("test string {0} {1}", j, i), "key"); 
       } 
       Console.WriteLine("j = {0}", j); 
      } 

      Console.WriteLine("Finished"); 
      Console.ReadLine(); 

     } 

     public static string Encrypt(string plainText, string key) 
     { 
      //Set up the encryption objects 
      byte[] encryptedBytes = null; 
      using (AesCryptoServiceProvider acsp = GetProvider(Encoding.UTF8.GetBytes(key))) 
      { 
       byte[] sourceBytes = Encoding.UTF8.GetBytes(plainText); 
       using (ICryptoTransform ictE = acsp.CreateEncryptor()) 
       { 
        //Set up stream to contain the encryption 
        using (MemoryStream msS = new MemoryStream()) 
        { 
         //Perform the encrpytion, storing output into the stream 
         using (CryptoStream csS = new CryptoStream(msS, ictE, CryptoStreamMode.Write)) 
         { 
          csS.Write(sourceBytes, 0, sourceBytes.Length); 
          csS.FlushFinalBlock(); 

          //sourceBytes are now encrypted as an array of secure bytes 
          encryptedBytes = msS.ToArray(); //.ToArray() is important, don't mess with the buffer 

          csS.Close(); 
         } 

         msS.Close(); 
        } 
       } 

       acsp.Clear(); 
      } 

      //return the encrypted bytes as a BASE64 encoded string 
      return Convert.ToBase64String(encryptedBytes); 
     } 
     private static AesCryptoServiceProvider GetProvider(byte[] key) 
     { 
      AesCryptoServiceProvider result = new AesCryptoServiceProvider(); 
      result.BlockSize = 128; 
      result.KeySize = 256; 
      result.Mode = CipherMode.CBC; 
      result.Padding = PaddingMode.PKCS7; 

      result.GenerateIV(); 
      result.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 

      byte[] RealKey = GetKey(key, result); 
      result.Key = RealKey; 
      // result.IV = RealKey; 
      return result; 
     } 

     private static byte[] GetKey(byte[] suggestedKey, SymmetricAlgorithm p) 
     { 
      byte[] kRaw = suggestedKey; 
      List<byte> kList = new List<byte>(); 

      for (int i = 0; i < p.LegalKeySizes[0].MaxSize; i += 8) 
      { 
       kList.Add(kRaw[(i/8) % kRaw.Length]); 
      } 
      byte[] k = kList.ToArray(); 
      return k; 
     } 

    } 
} 
+0

Dzięki Stevensowi za dodatkowy wysiłek. Przetestowałbym to na 4.0 –

+0

Tak, masz rację, że działa na 4.0, więc to znaczy, że to błąd ramy 3.5 ??? –

+0

No cóż, nie ma żadnego rozwiązania tego w netfx3.5, więc oznaczanie go jako odpowiedź, Dzięki Simonowi za pomoc. –

0

naprawdę nie próbuje porwać wątku ale jaka jest zasadnicza różnica między szyfrowania i ten jeden?


/// 
     /// Encrypts a string 
     /// 
     /// Text to be encrypted 
     /// Password to encrypt with 
     /// Salt to encrypt with 
     /// Can be either SHA1 or MD5 
     /// Number of iterations to do 
     /// Needs to be 16 ASCII characters long 
     /// Can be 128, 192, or 256 
     /// An encrypted string 
     public static string Encrypt(string PlainText, string Password, 
      string Salt, string HashAlgorithm, 
      int PasswordIterations, string InitialVector, 
      int KeySize) 
     { 
      try 
      { 
       if (string.IsNullOrEmpty(PlainText)) 
        return ""; 
       byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector); 
       byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt); 
       byte[] PlainTextBytes = Encoding.UTF8.GetBytes(PlainText); 
       PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations); 
       byte[] KeyBytes = DerivedPassword.GetBytes(KeySize/8); 
       RijndaelManaged SymmetricKey = new RijndaelManaged(); 
       SymmetricKey.Mode = CipherMode.CBC; 
       byte[] CipherTextBytes = null; 
       using (ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes)) 
       { 
        using (MemoryStream MemStream = new MemoryStream()) 
        { 
         using (CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write)) 
         { 
          CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length); 
          CryptoStream.FlushFinalBlock(); 
          CipherTextBytes = MemStream.ToArray(); 
          MemStream.Close(); 
          CryptoStream.Close(); 

          CryptoStream.Dispose(); 
          MemStream.Dispose(); 
         } 
        } 
        Encryptor.Dispose(); 
       } 
       SymmetricKey.Clear(); 
       return Convert.ToBase64String(CipherTextBytes); 
      } 
      catch { throw; } 
     } 

Uruchomiłem ten pod 3.5 i nie ruszył się poza 22mb. Moje umiejętności kryptograficzne są trochę cienkie, ale zastanawiam się ogólnie, dlaczego jedna jest lepsza od drugiej, czy też jest. Wydaje się, że wiele sposobów robi to samo.

Powiązane problemy