Oberon space

General Category => Общий раздел => Тема начата: Губанов Сергей Юрьевич от Март 16, 2012, 07:54:12 pm

Название: Утечка виртуальной памяти
Отправлено: Губанов Сергей Юрьевич от Март 16, 2012, 07:54:12 pm
Неожиданно столкнулся со следующей проблемой. Вот уже во второй раз (сегодня был один случай, и вчера) программа (под Mono 2.6.7) выжрала всю виртуальную память (3 ГБ) и при попытке выделить память под массив на 5 Мб кидает исключение OutOfMemory. Физической памяти занято сущие копейки -- всего 130 Мб. Под Виндос не воспроизводится. Что за напасть такая... Как бороться с утечками виртуальной памяти?

Планирую в понедельник добавить периодический вывод в лог количество виртуальной памяти, чтобы хоть понять в какое время она вырастает.

Кстати вопрос к знатокам Линукса: какую API функцию надо звать чтоб узнать количество занятой памяти? Читать псевдокаталог proc не хочу, должна же быть нормальная API функция.
Название: Re: Утечка виртуальной памяти
Отправлено: valexey от Март 16, 2012, 08:09:28 pm
man getrusage
Название: Re: Утечка виртуальной памяти
Отправлено: valexey от Март 16, 2012, 08:12:19 pm
Насколько я понимаю, идет утечна "адресного пространства". Ведь своп же не растет, так?
Быть может у вас там где-то mmap'ится что-то без последующего munmap?
Название: Re: Утечка виртуальной памяти
Отправлено: Romiras от Март 17, 2012, 11:20:34 am
Вчера искал...
Цитата: http://stackoverflow.com/questions/2513505/how-to-get-available-memory-c-g
#include <unistd.h>

long getTotalSystemMemory()
{
    long pages = sysconf(_SC_PHYS_PAGES);
    long page_size = sysconf(_SC_PAGE_SIZE);
    return pages * page_size;
}
При условии, что из Моно можно вызывать C функции.
Название: Re: Утечка виртуальной памяти
Отправлено: Губанов Сергей Юрьевич от Март 19, 2012, 05:43:27 am
man getrusage
Это оказалось не то, что нужно. В поле getrusage.ru_maxrss пишется реальная память, а мне нужна виртуальная.
Название: Re: Утечка виртуальной памяти
Отправлено: Губанов Сергей Юрьевич от Март 19, 2012, 11:12:37 am
Несколько часов гугления результата не дали. Так и пришлось читать псевдофайл "/proc/self/status", искать в нём строку начинающуюся на "VmSize:" и парсить её. Не ожидал я такой подставы от Линукса. Вот это да. Позор разработчикам линуксового API!!!
Название: Re: Утечка виртуальной памяти
Отправлено: Romiras от Март 19, 2012, 11:55:50 am
Несколько часов гугления результата не дали. Так и пришлось читать псевдофайл "/proc/self/status", искать в нём строку начинающуюся на "VmSize:" и парсить её. Не ожидал я такой подставы от Линукса. Вот это да. Позор разработчикам линуксового API!!!
И чего тут удивляться - типичный дистрибутив Линукса не обходится без Перла.   ;)
Название: Re: Утечка виртуальной памяти
Отправлено: vlad от Март 19, 2012, 02:27:21 pm
Несколько часов гугления результата не дали. Так и пришлось читать псевдофайл "/proc/self/status", искать в нём строку начинающуюся на "VmSize:" и парсить её. Не ожидал я такой подставы от Линукса. Вот это да. Позор разработчикам линуксового API!!!

Я так понимаю (после тесного знакомства c OSX) - это вполне нормальная ситуация в юникс системах. Не парься :) Сам прибегал к подобным решениям неоднократно. Проблемы тоже понятно какие - выходит новая версия с другим форматированием...
Название: Re: Утечка виртуальной памяти
Отправлено: valexey от Март 19, 2012, 05:27:29 pm
Посмотрел исходники top и atop - таки они под линуксом реально парсят /proc/pid/stat. К сожалению этот способ не описан в ISO-стандарте LSB (Linux standard base), не говоря уже о SUS (Single unix specification). Соответственно это действительно может измениться (как впрочем и любой API который туда не входит. То есть нет разницы в плане надежности и неизменности API это или же какой-то псевдофайл текстовый. Причем не стандартизированное API обычно меняется более резво чем текстовое файло, ибо затрагивает только программистов, а файло еще и сисадминов-скриптовиков).

Собственно дока по этому делу тут: http://www.kernel.org/doc/man-pages/online/pages/man5/proc.5.html Там же сказано и в какой исходник смотреть на предмет изменения.
Название: Re: Утечка виртуальной памяти
Отправлено: valexey от Март 19, 2012, 05:29:11 pm
Несколько часов гугления результата не дали. Так и пришлось читать псевдофайл "/proc/self/status", искать в нём строку начинающуюся на "VmSize:" и парсить её. Не ожидал я такой подставы от Линукса. Вот это да. Позор разработчикам линуксового API!!!

Я так понимаю (после тесного знакомства c OSX) - это вполне нормальная ситуация в юникс системах. Не парься :) Сам прибегал к подобным решениям неоднократно.
Ну, ты таки немного лукавишь - бОльшая часть геморроев с OSX у тебя как раз из за необходимости поддерживать древнюю версию которая как раз еще не Unix. А вот начиная с Unix-версии, все стало существенно лучше. :-)
Название: Re: Утечка виртуальной памяти
Отправлено: vlad от Март 19, 2012, 05:34:17 pm
Посмотрел исходники top и atop - таки они под линуксом реально парсят /proc/pid/stat. К сожалению этот способ не описан в ISO-стандарте LSB (Linux standard base), не говоря уже о SUS (Single unix specification). Соответственно это действительно может измениться (как впрочем и любой API который туда не входит. То есть нет разницы в плане надежности и неизменности API это или же какой-то псевдофайл текстовый

Таки ты тоже  немного лукавишь ;) В случае API - сломается компиляция, в отличие от ;)
Название: Re: Утечка виртуальной памяти
Отправлено: valexey от Март 19, 2012, 05:35:58 pm
Кстати, сама /proc в линуксе слизана с Plan9, которая, в свою очередь, расширила и углубила идею /proc из Unix v8 (1984 год: http://man.cat-v.org/unix_8th/4/proc ).
Название: Re: Утечка виртуальной памяти
Отправлено: valexey от Март 19, 2012, 05:40:01 pm
Посмотрел исходники top и atop - таки они под линуксом реально парсят /proc/pid/stat. К сожалению этот способ не описан в ISO-стандарте LSB (Linux standard base), не говоря уже о SUS (Single unix specification). Соответственно это действительно может измениться (как впрочем и любой API который туда не входит. То есть нет разницы в плане надежности и неизменности API это или же какой-то псевдофайл текстовый

Таки ты тоже  немного лукавишь ;) В случае API - сломается компиляция, в отличие от ;)
Это не обязательно. В некоторых случаях компиляция может и не сломаться :-) Тем более что уже скомпиленное в случае изменения API схлопочет сегфолт (в лучшем случае).

В случае текстового файла скрипты тоже сломаются, если например число параметров станет другим, или их формат поменяется. Хотя может и не сломаться, а начать просто выводить чушь, что ЕЩЕ ХУЖЕ.

;-)
Название: Re: Утечка виртуальной памяти
Отправлено: Губанов Сергей Юрьевич от Март 20, 2012, 07:58:01 am
Немножко исходников

      private static class Linux
      {
        public static void GetMemorySize (out long virtualSize, out long residentSize)
        {
          const string VmSize = "VmSize:";
          const string VmRSS = "VmRSS:";
          virtualSize = 0;
          residentSize = 0;
          using (System.IO.StreamReader rd = System.IO.File.OpenText("/proc/self/status"))
          {
            while (!rd.EndOfStream && ((virtualSize == 0) || (residentSize == 0)))
            {
              string line = rd.ReadLine();
              if (line.StartsWith(VmSize))
              {
                string s = line.Substring(VmSize.Length, line.Length - VmSize.Length - 3);
                long x;
                long.TryParse(s, out x);
                virtualSize = x * 1024;
              }
              else if (line.StartsWith(VmRSS))
              {
                string s = line.Substring(VmRSS.Length, line.Length - VmRSS.Length - 3);
                long x;
                long.TryParse(s, out x);
                residentSize = x * 1024;
              }
            }
          }
        }
      }

      private static class Win64
      {
        private struct PROCESS_MEMORY_COUNTERS_EX
        {
          public uint cb;
          public uint PageFaultCount;
          public ulong PeakWorkingSetSize;
          public ulong WorkingSetSize;
          public ulong QuotaPeakPagedPoolUsage;
          public ulong QuotaPagedPoolUsage;
          public ulong QuotaPeakNonPagedPoolUsage;
          public ulong QuotaNonPagedPoolUsage;
          public ulong PagefileUsage;
          public ulong PeakPagefileUsage;
          public ulong PrivateUsage;
        }

        [System.Runtime.InteropServices.DllImport("Psapi.dll")]
        private static extern long GetProcessMemoryInfo (long process, ref PROCESS_MEMORY_COUNTERS_EX x, uint cb);

        [System.Runtime.InteropServices.DllImport("Kernel32.dll")]
        private static extern long GetCurrentProcess ();

        public static void GetMemorySize (out long virtualSize, out long residentSize)
        {
          PROCESS_MEMORY_COUNTERS_EX x = new PROCESS_MEMORY_COUNTERS_EX();
          x.cb = 80;
          GetProcessMemoryInfo(GetCurrentProcess(), ref x, 80);
          virtualSize = (long)x.PrivateUsage;
          residentSize = (long)x.WorkingSetSize;
        }
      }
Название: Re: Утечка виртуальной памяти
Отправлено: Губанов Сергей Юрьевич от Март 20, 2012, 11:16:51 am
Посмотрел исходники top и atop - таки они под линуксом реально парсят /proc/pid/stat.
А ты случайно не обратил внимание на то, с какой максимальной частотой они туда могут смотреть? Хочется узнать с какой максимальной частотой имеет смысл смотреть в proc. Я сейчас это делаю 10 раз в секунду, но вдруг там данные обновляются реже? Тогда и я реже буду смотреть.
Название: Re: Утечка виртуальной памяти
Отправлено: valexey от Март 20, 2012, 02:05:56 pm
Посмотрел исходники top и atop - таки они под линуксом реально парсят /proc/pid/stat.
А ты случайно не обратил внимание на то, с какой максимальной частотой они туда могут смотреть? Хочется узнать с какой максимальной частотой имеет смысл смотреть в proc. Я сейчас это делаю 10 раз в секунду, но вдруг там данные обновляются реже? Тогда и я реже буду смотреть.
По моему, они там не парятся с этим делом. То есть какой-нибудь top просто раз в секунду (по умолчанию) перечитывает все. А не по умолчанию интервал задается пользователем. То есть отдано на откуп юзеру.

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

PS. /proc/[pid]/status предназначен для чтения человеком. А для парсинга вроде как больше предназначены /proc/[pid]/statm и /proc/[pid]/stat (см тут: http://www.kernel.org/doc/man-pages/online/pages/man5/proc.5.html). Там просто набор чисел разделенных пробелом.