Oberon space
General Category => Общий раздел => Тема начата: Губанов Сергей Юрьевич от Март 16, 2012, 07:54:12 pm
-
Неожиданно столкнулся со следующей проблемой. Вот уже во второй раз (сегодня был один случай, и вчера) программа (под Mono 2.6.7) выжрала всю виртуальную память (3 ГБ) и при попытке выделить память под массив на 5 Мб кидает исключение OutOfMemory. Физической памяти занято сущие копейки -- всего 130 Мб. Под Виндос не воспроизводится. Что за напасть такая... Как бороться с утечками виртуальной памяти?
Планирую в понедельник добавить периодический вывод в лог количество виртуальной памяти, чтобы хоть понять в какое время она вырастает.
Кстати вопрос к знатокам Линукса: какую API функцию надо звать чтоб узнать количество занятой памяти? Читать псевдокаталог proc не хочу, должна же быть нормальная API функция.
-
man getrusage
-
Насколько я понимаю, идет утечна "адресного пространства". Ведь своп же не растет, так?
Быть может у вас там где-то mmap'ится что-то без последующего munmap?
-
Вчера искал...
#include <unistd.h>
long getTotalSystemMemory()
{
long pages = sysconf(_SC_PHYS_PAGES);
long page_size = sysconf(_SC_PAGE_SIZE);
return pages * page_size;
}
При условии, что из Моно можно вызывать C функции.
-
man getrusage
Это оказалось не то, что нужно. В поле getrusage.ru_maxrss пишется реальная память, а мне нужна виртуальная.
-
Несколько часов гугления результата не дали. Так и пришлось читать псевдофайл "/proc/self/status", искать в нём строку начинающуюся на "VmSize:" и парсить её. Не ожидал я такой подставы от Линукса. Вот это да. Позор разработчикам линуксового API!!!
-
Несколько часов гугления результата не дали. Так и пришлось читать псевдофайл "/proc/self/status", искать в нём строку начинающуюся на "VmSize:" и парсить её. Не ожидал я такой подставы от Линукса. Вот это да. Позор разработчикам линуксового API!!!
И чего тут удивляться - типичный дистрибутив Линукса не обходится без Перла. ;)
-
Несколько часов гугления результата не дали. Так и пришлось читать псевдофайл "/proc/self/status", искать в нём строку начинающуюся на "VmSize:" и парсить её. Не ожидал я такой подставы от Линукса. Вот это да. Позор разработчикам линуксового API!!!
Я так понимаю (после тесного знакомства c OSX) - это вполне нормальная ситуация в юникс системах. Не парься :) Сам прибегал к подобным решениям неоднократно. Проблемы тоже понятно какие - выходит новая версия с другим форматированием...
-
Посмотрел исходники 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 Там же сказано и в какой исходник смотреть на предмет изменения.
-
Несколько часов гугления результата не дали. Так и пришлось читать псевдофайл "/proc/self/status", искать в нём строку начинающуюся на "VmSize:" и парсить её. Не ожидал я такой подставы от Линукса. Вот это да. Позор разработчикам линуксового API!!!
Я так понимаю (после тесного знакомства c OSX) - это вполне нормальная ситуация в юникс системах. Не парься :) Сам прибегал к подобным решениям неоднократно.
Ну, ты таки немного лукавишь - бОльшая часть геморроев с OSX у тебя как раз из за необходимости поддерживать древнюю версию которая как раз еще не Unix. А вот начиная с Unix-версии, все стало существенно лучше. :-)
-
Посмотрел исходники top и atop - таки они под линуксом реально парсят /proc/pid/stat. К сожалению этот способ не описан в ISO-стандарте LSB (Linux standard base), не говоря уже о SUS (Single unix specification). Соответственно это действительно может измениться (как впрочем и любой API который туда не входит. То есть нет разницы в плане надежности и неизменности API это или же какой-то псевдофайл текстовый
Таки ты тоже немного лукавишь ;) В случае API - сломается компиляция, в отличие от ;)
-
Кстати, сама /proc в линуксе слизана с Plan9, которая, в свою очередь, расширила и углубила идею /proc из Unix v8 (1984 год: http://man.cat-v.org/unix_8th/4/proc ).
-
Посмотрел исходники top и atop - таки они под линуксом реально парсят /proc/pid/stat. К сожалению этот способ не описан в ISO-стандарте LSB (Linux standard base), не говоря уже о SUS (Single unix specification). Соответственно это действительно может измениться (как впрочем и любой API который туда не входит. То есть нет разницы в плане надежности и неизменности API это или же какой-то псевдофайл текстовый
Таки ты тоже немного лукавишь ;) В случае API - сломается компиляция, в отличие от ;)
Это не обязательно. В некоторых случаях компиляция может и не сломаться :-) Тем более что уже скомпиленное в случае изменения API схлопочет сегфолт (в лучшем случае).
В случае текстового файла скрипты тоже сломаются, если например число параметров станет другим, или их формат поменяется. Хотя может и не сломаться, а начать просто выводить чушь, что ЕЩЕ ХУЖЕ.
;-)
-
Немножко исходников
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;
}
}
-
Посмотрел исходники top и atop - таки они под линуксом реально парсят /proc/pid/stat.
А ты случайно не обратил внимание на то, с какой максимальной частотой они туда могут смотреть? Хочется узнать с какой максимальной частотой имеет смысл смотреть в proc. Я сейчас это делаю 10 раз в секунду, но вдруг там данные обновляются реже? Тогда и я реже буду смотреть.
-
Посмотрел исходники 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). Там просто набор чисел разделенных пробелом.