.NET 中 MD5 編碼的內存泄露問題分析

jopen 8年前發布 | 8K 次閱讀 加密解密 .NET開發 .NET

問題描述與定位

最近一個項目中要加工處理700多萬條的三元組數據,總是在執行到二三百萬條的時候就報內存溢出了。不斷的檢查代碼,各種對象局部化;使用.net profiler分析堆棧內存,發現有大量的String對象創建沒有及時回收,于是對程序中各處的字符串拼接做了優化處理,但是結果不是很明顯,還是會出現內存溢出的情況,只不過出現的晚一點。

又經過反復的對代碼段注釋測試,最后定位到可能出現內存泄露的函數(被調用700萬次以上)如下:

        public static string MD5Encode(string source)
        {
            if (string.IsNullOrEmpty(source))
                return source;

            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(source));
            return BitConverter.ToString(s).Replace("-", "");
        }

分別注釋8、7、6行代碼,發現只有md5對象的創建時候,還是會出現內存溢出。OK,最后確定造成內存泄露的對象就是MD5CryptoServiceProvider。

問題解決

找到問題的原因了,就開始嘗試解決辦法,既然MD5CryptoServiceProvider對象的創建會造成內存泄露,就只創建一個對象實例試試(單例化),修改后,代碼如下(代碼相對簡單,注釋已移除):

        public static string MD5Encode(string source)
        {
            if (string.IsNullOrEmpty(source))
                return source;

            MD5 md5 = GetMd5Instance();
            byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(source));
            return BitConverter.ToString(s).Replace("-", "");
        }

        private static MD5CryptoServiceProvider _md5Instance;
        private MD5CryptoServiceProvider GetMd5Instance()
        {
            return _md5Instance ?? (_md5Instance = new MD5CryptoServiceProvider());
        }

經過幾輪測試,沒有再出現內存溢出,問題解決了。

原理依據

既然 MD5CryptoServiceProvider會造成內存泄露,肯定是要有原因的,微軟也給出了提示,這個類是非線程安全的。MSDN的描述如下:

使用建議

既然 MD5CryptoServiceProvider的實例是非線程安全的,使用單例模式也是一種辦法。同時,如果不考慮和老系統的兼容問題,請使用新的取hash的算法sha,MSDN上面也有建議:

SHA1、SHA384、SHA256、SHA512都有線程安全的子類:{X}Managed,可以使用這樣的子類放心創建實例:

        public static string Md5Encode(string source)
        {
            if (string.IsNullOrEmpty(source))
                return source;

            //MD5 md5 = GetMd5Instance();
            //byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(source));

            SHA512 shaM = new SHA512Managed();
            byte[] s = shaM.ComputeHash(Encoding.UTF8.GetBytes(source));

            //SHA1 shaM = new SHA1Managed();
            //byte[] s = shaM.ComputeHash(Encoding.UTF8.GetBytes(source));

            return BitConverter.ToString(s).Replace("-", "");
        }

當然, {X} CryptoServiceProvider類型的實例依然是非線程安全的,要是使用 {X} CryptoServiceProvider,仍然要注意內存泄露問題。

來自: http://my.oschina.net/u/1052456/blog/552942?fromerr=KuQNR4Wc

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!