почему этот код вызывает утечку памяти? - PullRequest
8 голосов
/ 04 июня 2011

Я недавно стал владельцем службы Windows WCF, которая интенсивно использует следующий статический класс Utility для извлечения данных поиска:

   public static class Utility
    {

       //begin code that causes increased memory consumption
        private static Dictionary<string, ErrorData> _errorData;

        internal static Dictionary<string, ErrorData> ErrorData

        {
            get
            {
                if (_errorData == null)
                {
                    _errorData = GetErrorData();
                }
                return _errorData;
            }

        }
        //end code that causes increased memory consumption

        /// GetErrorData method to get error messages from error xml
        /// </summary>         
        /// <returns>Dictionary of Error messages value for different fields.</returns>           
        internal static Dictionary<string, ErrorData> GetErrorData()
        {
            Dictionary<string, ErrorData> data = null;


                XmlDocument doc = LoadXmlDocument(Constants.ErrorMessagesFileName);
                XmlNodeList errorNode = doc.SelectNodes("/ErrorMessages/Error");
                data = new Dictionary<string, ErrorData>();

                foreach (XmlNode node in errorNode)
                {
                    ErrorData errorValues = new ErrorData();
                    errorValues.FieldName = node.Attributes["FieldName"].Value;
                    errorValues.ErrorMessage = node.Attributes["ErrorMessage"].Value;
                    data.Add(node.Attributes["code"].Value, errorValues);
                }


            return data;
        }
        internal static XmlDocument LoadXmlDocument(string xmlFileName)
        {
            XmlDocument doc = null;
            try
            {
                if (HttpRuntime.Cache[xmlFileName] == null)
                {
                    doc = new XmlDocument();
                    doc.Load(Constants.Folderpath + "\\" + xmlFileName);
                    HttpRuntime.Cache.Insert(xmlFileName, doc);
                }
                else
                {
                    doc = (XmlDocument)HttpRuntime.Cache[xmlFileName];
                }
            }
            catch (Exception ex)
            {
               //log
            }
            return doc;
        }
    }

Как видите, статическое свойство ErrorData используетчастное поле поддержки.ErrorData - это словарь, который создается с использованием ресурса XML в файловой системе, поэтому содержимое файла сохраняется в HttpRuntime.Cache при первоначальном извлечении.

При нормальной нагрузке служба потребляет около 120 МБ ОЗУ.

В какой-то момент член команды почувствовал необходимость ввести другой уровень оптимизации, создав статическое свойство, поддерживаемое ленивозагружено статическое поле.В любом случае, наличие указанного статического поля вызывает довольно серьезную утечку памяти (500 МБ +) после нескольких обращений в службу.

Когда я удаляю статическое поле и свойство (клиенты вместо этого вызывают Utility.GetErrorData ()), потребление памяти возвращается к нормальному уровню.

Может кто-нибудь объяснить, почему наличие этого статического полявызывает утечку памяти?Служба WCF работает с InstanceContextMode.PerCall, если это имеет значение.

Большое спасибо.

Ответы [ 4 ]

1 голос
/ 20 июля 2011

Если файл ошибок очень большой, то статическая версия загружает огромный XML-документ в память и никогда не выпускает его.Ранее, если бы клиенты вызывали GetErrorData (), тогда данные были бы загружены в память и возвращены, очищая память.

Здесь нет синхронизации, поэтому если статическая переменная не была загружена, несколько одновременных запросовначали загружать документ об ошибке отдельно.Только один словарь победит и будет сохранен в статической переменной.Однако, если файл ошибок большой, загрузка нескольких потоков одновременно приведет к увеличению нагрузки на память.Если бы это было так, я ожидал бы, что следующая сборка мусора освободит дополнительные экземпляры и освободит большую часть этой памяти.

Также обратите внимание, что версия статического экземпляра загружает файл ошибок один раз.Поэтому, если будут созданы дополнительные ошибки, они никогда не будут возвращены клиенту.

0 голосов
/ 24 августа 2011

Исправляет ли добавление синхронизации вашу «утечку памяти»?

То есть, например, сделать LoadXmlDocument () и GetErrorData () как private и изменить свойство ErrorData примерно так1005 * Примечание. Обычно утечка памяти означает, что приложение медленно со временем потребляет все больше и больше памяти (что никогда не восстанавливается).Это то, что вы наблюдаете, или ваше потребление памяти становится выше, хотя и стабильным, когда вы меняете реализацию?Чтобы действительно удостовериться, что у вас действительно есть утечка памяти и какова реальная причина (какие объекты не могут быть собраны / завершены), вам часто придется использовать профилировщик памяти.

0 голосов
/ 27 июля 2011

Попробуйте взять дамп вашего w3p-процесса и проверить, что там находится в куче больших объектов и какие объекты занимают большой кусок памяти.это поможет вам точно определить причину утечки памяти.

, вам также следует проверить сборки, загруженные в память.XMLserializer является одним из примеров.

См. Блог Тесс об утечке памяти.http://blogs.msdn.com/b/tess/archive/2008/03/17/net-debugging-demos-lab-6-memory-leak.aspx

0 голосов
/ 06 июня 2011

Я не совсем уверен, какое изменение кода вы имеете в виду, когда говорите об этом изменении. Однако, читая код, я предполагаю, что в итоге вы вызываете GetErrorData более одного раза, и словарь просто наполняется множеством повторяющихся записей. Если вы добавляете код регистрации, какой код вводится повторно?

Martyn

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...