Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Как узнать RAM Usage (использование оперативки) какого-нибудь процесса в .NET?

408
27 февраля 2009 года
Lei fang
265 / / 01.10.2005
Здравствуйте, есть собственно такая задача, узнать сколько оперативной памяти использует тот или иной процесс. Известно имя процесса.
Запускается процесс с помощью класса ProcessStartInfo и Process. Есть ли в си шарпе какие-то функции чтобы узнать это? Или АПИ? Если знаете подскажите как.

Благодарю.
5
27 февраля 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: Lei fang
Запускается процесс с помощью класса ProcessStartInfo и Process.

Вот члены класса Process и смотрите. Автокомплит вам в помощь. ;)

408
27 февраля 2009 года
Lei fang
265 / / 01.10.2005
Упс. А я посмотрел в ProcessStartInfo, не нашел и решил спросить. Чего-то меня переклинило и не посмотрел что можно сделать с процессом самим :) Спасибо
408
22 марта 2009 года
Lei fang
265 / / 01.10.2005
М... пробую различные вещи и получаю всегда разные результаты lol, для одного и того же экзешника...
Там этих мемори юзаджей у Процесс так много. Может кто-то точно сказать как узнать сколько памяти использует экзешник?

ReturnValues[2] = (p.PeakVirtualMemorySize64 + p.PeakWorkingSet64).ToString();
Пробую так, результат всегда разный. И не только так пробовал...
5
22 марта 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: Lei fang
М... пробую различные вещи и получаю всегда разные результаты lol, для одного и того же экзешника...
Там этих мемори юзаджей у Процесс так много. Может кто-то точно сказать как узнать сколько памяти использует экзешник?

ReturnValues[2] = (p.PeakVirtualMemorySize64 + p.PeakWorkingSet64).ToString();
Пробую так, результат всегда разный. И не только так пробовал...



Проситите, но вы документацию-то читали?
PeakXXX возвращает пиковое значение параметра XXX, которое когда либо было достигнуто процессом.

Любой процесс занимает некоторое количество виртуальной памяти, она включает в себя выделенную физическую, еще не выделенную ОС вообще, а также область в файле подкачки (выделенная память, но сброшенная туда ввиду нехватки ОЗУ).

Так вот, физическая память, выделенная процессу называется WorkingSet, а вообще вся память процесса - виртуальная память VirtualMemorySize.

Размер WorkingSet можно ограничить снизу (MinWorkingSet) и сверху (MaxWorkingSet), если процесс затребует больше физической памяти, чем его MaxWorkingSet, то часть ворк-сета будет сброшена в файл подкачки.

408
22 марта 2009 года
Lei fang
265 / / 01.10.2005
Я пытался читать документацию... К сожалению ясных представлений о том из чего именно состоит используемая память процессом я не имею (за исключением данных находящихся в оперативке и HDD), поэтому немного понял, чем отличается то или иное поле относящееся к памяти.

Кстати мне и надо получить максимальное использование оперативки, беда лишь в том, что я пытаюсь вычислить ее одинаково, для одинакового процесса, а получаю каждый раз значения, превосходящие порой на 300% предыдущее значение.

М... на сколько я понял (может быть и не верно) мне надо юзать PeakVirtualMemorySize64.

Может дело правда в том, что я провожу измерения памяти каждые 50 мс. И тут как-о сказывается время когда измеряю. Но как иначе получить дейстьвительное максимальное значение памяти, если когда процесс завершил работу, попытки получить значение этих полей заканчивается ошибкой, что процесс уже завершился?
38K
29 марта 2009 года
alt@zir
29 / / 28.08.2008
Используйте набор функций tool help из platform sdk.
408
03 апреля 2009 года
Lei fang
265 / / 01.10.2005
Можно приветси хотя бы одно название функции из этого tool help из platform sdk?
гугл не знает что такое tool help, tool help c#, tool help sdk
я тоже. где и как узнать что это тоже не знаю
5
03 апреля 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: Lei fang
Можно приветси хотя бы одно название функции из этого tool help из platform sdk?
гугл не знает что такое tool help, tool help c#, tool help sdk
я тоже. где и как узнать что это тоже не знаю


Класс Process фактически обертка над ними. Искать надо в МСДН.

38K
03 апреля 2009 года
alt@zir
29 / / 28.08.2008
Цитата: Lei fang
Можно приветси хотя бы одно название функции из этого tool help из platform sdk?...



CreateToolhelp32Snapshot
смотри в MSDN и заголовок tlhelp32.h
алгоритм для подсчета будет приблизительно такой:
1) делаем снимок
2) прыгаем на первую кучу из списка
3) прыгаем на первый блок из кучи и берем его размер
4) прыгаем на следующий блок и сумируем его размер с предыдущим
5) повторяем шаг 4 пока не закончятся блоки
6) прыгаем на следующую кучу
7) повторяем шаг 3, 4, 5 для нее)
....
думаю дальше понятно

будет время заморочусь и сделаю пример;)

как в С# не знаю...

408
03 апреля 2009 года
Lei fang
265 / / 01.10.2005
о Господи :)
Это очень круто, но как это поможет мне определить именно максимальное использование памяти? Ведь если проверять интервалами, то я могу упустить максимальное использование памяти, когда наступает пик и процесс завершается до следующей проверки
проверяю уже и так раз в миллисекунду.

Делать цикл без задержки это вообще ужас, ибо одновременно прийдется проверять от одного процесса до n процессов. А использование CPU будет 100%

Как бы получить максимальное использование памяти прямо перед завершением работы процесса.
38K
03 апреля 2009 года
alt@zir
29 / / 28.08.2008
тьфу ты... всего то... юзай PSAPI

вот тебе примерчик сделал С++:)
думаю с остальными полями структуры разберешься:)
Код:
#include <windows.h>

#include <psapi.h>
#pragma comment (lib, "psapi.lib")

#include <iostream>




int main (void)
{  
    // берем хэндл на процесс
    HANDLE hProcess = GetCurrentProcess();
    // инициализируем структуру
    PROCESS_MEMORY_COUNTERS pmc;
    ZeroMemory(&pmc, sizeof(PROCESS_MEMORY_COUNTERS));
   
    // заполняем структуру инфой о нужном нам процессе
    GetProcessMemoryInfo(hProcess, &pmc, sizeof(PROCESS_MEMORY_COUNTERS));

    std::cout << "Peak usage: " << pmc.PeakWorkingSetSize / 1024 << "kb" << std::endl;
    std::cout << "Current usage: " << pmc.WorkingSetSize / 1024 << "kb" << std::endl;

    return 0;
}
408
04 апреля 2009 года
Lei fang
265 / / 01.10.2005
Премного благодарен за примерчик, он мне пригодится когда буду решать подобные задачи на с++ (занимаюсь собирательством полезных исходников :P), а так по сути он аналогичен Process.Peakxxxxxxx...
И мне по прежнему не ясно, как он мне поможет определить макс РАМ прямо перед завершением процесса. Не своего конечно же, а чужого, который я сам запускаю и сам мониторю. Может есть какие-то события что процесс собирается завершиться, но пока не завершился можно узнать его РАМ юзаж, или можно прервать завершение работы процесса (допустим в ilde его перевести, или ожидание ввода или еще чего-то), измерить оперативку и завершить его работу или может какая-то статистика в ОС есть, откуда можно взять инфу о уже завершившемся процесе (Я не знаю возможно ли это все...)

твой пример конечно определяет именно максимальное использование РАМ и именно в конце работы процесса, но своего, а мне надо чужого...
38K
05 апреля 2009 года
alt@zir
29 / / 28.08.2008
Короче заморочился по твоей теме и накидал еще один пример...
Смысл его в том что мы внедряем в нужный нам процесс библиотеку (шпионский модуль). Перед завершением процесса система всегда вызывает из спроецированных в адресное пространство процесса библиотек функцию DllMain с параметром DLL_PROCESS_DETACH, вот в этом месте мы и собираем нужную нам статистику, а в это время наша программа которая внедрила шпионский модуль ожидает завершения процесса, как только процесс завершился, она открывает файл в который шпионский модуль записал нужную нам инфу и читает.

остальные объяснения в коментарияx к коду

прога внедряющая модуль:
Код:
#include <windows.h>
#include <string.h>

// подключаем toolhelp32 и PSAPI
#include <tlhelp32.h>
#include <psapi.h>
#pragma comment (lib, "psapi.lib")

// не бум заморачиваться с окнами, в данном контексте нам это не нужно
#include <iostream>


// используя toolhelp32 напишем функцию которая будет нам возвращать идентификатор
// процесса по имени, если функция завершилась удачно, возвращаем идентификатор процесса
// в противном случае возвращаем -1 и устанавливаем коды ошибок
#define A_SUCCES                    0x0     // все нормально
#define A_PROCESS_NOT_FOUND         0x1     // процесс с заданным именем не существует
#define A_FUNCTION_INTERNAL_ERROR   0x2     // внутренняя ошибка функции(невозможно сделать снимок и т.д.)
       
DWORD GetProcessByName(const char* proc_name)
{
    // делаем снимок процессов
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
   
    // проверяем что все нормально
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        // если не удалось создать снимок, устанавливаем код ошибки (внутренняя ошибка)
        SetLastError(A_FUNCTION_INTERNAL_ERROR);
        // и выходим
        return -1;
    }

    // со снимком все нормально идем дальше

    // инициализируем структуру PROCESSENTRY32
    PROCESSENTRY32 pe32;
    ZeroMemory(&pe32, sizeof(PROCESSENTRY32));
    pe32.dwSize = sizeof(PROCESSENTRY32);

   
   
    // прыгаем на первый процесс
    BOOL bError;
    bError = Process32First(hSnapshot, &pe32);
    if (bError == FALSE) {
        SetLastError(A_FUNCTION_INTERNAL_ERROR);
        return -1;
    }


    // сравниваем
    if ((::strcmp(pe32.szExeFile, proc_name))== 0) {
        CloseHandle(hSnapshot);
        SetLastError(A_SUCCES);
        return pe32.th32ProcessID;
    }


    // перебираем процессы дальше

    while (bError!= FALSE) {
       
        bError = Process32Next(hSnapshot, &pe32);

        if ((::strcmp(pe32.szExeFile, proc_name)) == 0) {
            CloseHandle(hSnapshot);
            SetLastError(A_SUCCES);
            return pe32.th32ProcessID;
        }
    }
    // процесс с заданным именем не найден
    SetLastError(A_PROCESS_NOT_FOUND);
    return -1;
}






int main (void)
{  


    char *proc_n = "calc.exe";
    char *spy_mod = "D:\\Development\\spymod.dll";
    char *spy_info_file = "D:\\spyinfo.spy";
    int length_spy_mod = ::strlen(spy_mod) + 1;


    // ищем нужный процесс и обрабатываем ошибки
    DWORD pid = GetProcessByName(proc_n);
    if (pid == -1) {
        if (GetLastError() == A_PROCESS_NOT_FOUND) {
            std::cout << "Process " << proc_n << " not found" << std::endl;
            return 0;
        } else {
            std::cout << "Error in function GetProcessByName. Need to Debug" << std::endl;
            return 0;
        }
    }
   
    // нужно же что-то сообщить
    std::cout << "Process " << proc_n << " found with ID = " << pid << std::endl;

    // подготавливаемся к внедрению нашего шпиона в адресное пространство изучаемого процесса
   

   
    // оттолкнемся от того, что скорее всего kernel32.dll расположен в адресном пространство изучаемого
    // процеса по тому же базовому адресу что и в нашем
    PVOID pfLoadLibraryA = GetProcAddress(GetModuleHandle("kernel32"), "LoadLibraryA");

    // пытаемся открыть нужный нам процес с правами на создание потоков и блоков памяти,
    // а также записи в память и синхронизации
    HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | SYNCHRONIZE,
        FALSE, pid);
    // здесь стоит проверить, получили ли мы дескриптор, потому что для некоторых
    // процессов система нам может отказать в открытии с такими правами
    // пока забьем на это, ибо не думаю что калькулятор представляет особую ценность для безопасности системы


    // теперь воспользуясь тем что прототип функции процесса и прототип LoadLibraryA выглядят очень и очень схоже
    // заставим исследуемый процесс загрузить нашего шпиона в свое адресное пространство, для этого:
    // 1) создадим в его адресном пространстве блок памяти и запишем туда строку с именем нашего шпиона
    char* remote_buf =(char*) VirtualAllocEx(hProcess, NULL, length_spy_mod, MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(hProcess, remote_buf, spy_mod, length_spy_mod, NULL);

    // 2) создадим в нем поток, подсунув адрес LoadLibraryA, вместо функции потока
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0,(LPTHREAD_START_ROUTINE) pfLoadLibraryA, remote_buf, 0, NULL);

    //3) ожидаем завершения работы потока
    WaitForSingleObject(hThread, INFINITE);
   
    //4) освобождаем выделенную память
    VirtualFreeEx(hProcess, remote_buf, 0, MEM_RELEASE);

    //5) все наш шпион успешно внедрен, сообщим об этом
    std::cout << "spymod.dll successfuly injected in " << proc_n << std::endl;
    std::cout << "Waiting process" << std::endl;

    // теперь нам осталось дождаться завершения процесса и прочесть данные собранные шпионом
    WaitForSingleObject(hProcess, INFINITE);

    std::cout << proc_n << " terminated" << std::endl;

    // прочтем данные собранные нашим шпионом
    PROCESS_MEMORY_COUNTERS pmc;
    ZeroMemory(&pmc, sizeof(PROCESS_MEMORY_COUNTERS));
    DWORD nb;
    HANDLE hSpyFile = CreateFile(spy_info_file, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    ReadFile(hSpyFile, &pmc, sizeof(pmc), &nb, NULL);
    CloseHandle(hSpyFile);

    // и выведем нужные нам
    std::cout << "Max process memory usage: " << pmc.PeakWorkingSetSize / 1024 << std::endl;
   

    return 0;
}


библиотека шпион:
Код:
#include <windows.h>


// подключаем PSAPI
#include <psapi.h>
#pragma comment (lib, "psapi.lib")

BOOL WINAPI
DllMain (HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
{
    char *spy_info_file = "D:\\spyinfo.spy";
    HANDLE hSpyInfo;

    // при завершении процесса система вызовет DllMain с причиной DLL_PROCESS_DETACH
    if (fdwReason == DLL_PROCESS_DETACH)
    {
       
        // проинициализируем структуру PROCESS_MEMORY_COUNTERS
        PROCESS_MEMORY_COUNTERS pmc;
        ZeroMemory(&pmc, sizeof(PROCESS_MEMORY_COUNTERS));

        // заполним ее данными о текущем процессе
        GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(PROCESS_MEMORY_COUNTERS));

           
        // запишем данные о процессе в наш файлик
        DWORD nb;
        hSpyInfo = CreateFile(spy_info_file, FILE_ALL_ACCESS, 0, NULL, CREATE_ALWAYS, NULL, NULL);
        WriteFile(hSpyInfo, &pmc, sizeof(pmc), &nb, NULL);
        CloseHandle(hSpyInfo);

    }
   

    return TRUE;
}


в примере шпион внедряется в обычный виндовский калькулятор.

Компилировать без юникода, ну и пути поменять на свои.
408
06 апреля 2009 года
Lei fang
265 / / 01.10.2005
Жаль тут нет смайла с выпученными глазами, но представь себе что это он: О_О
Полноценная статья по внедрению длл :)
Все очень подробно и как надо :) Премного благодарен!!!

Единстенный вопрос что у меня возникает, длл шпион можно внедрить в любое приложение? Т.е. дос / вин32 / .нет? На сколько я знаю есть определенные сложности в том, чтобы заставить .нет приложение использовать натив длл, да и наоборот наверное, если натив экзе заставить загрузить .нет сборку. Это так для развития :P

Хотя... Ведь сам процесс это уже натив код, может и не будет проблем с внедрением :)

Осталось это переписать на c# и будет мне счастье :D
5
06 апреля 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: Lei fang
Осталось это переписать на c# и будет мне счастье :D

Легко:

Код:
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace ConsoleApplication11 {
    class Program {
        static void Main(string[] args) {
            List<Process> processes = new List<Process>(Process.GetProcesses());
            foreach (Process process in processes) {
                process.Exited += delegate(object sender, EventArgs e) {
                    Process exited_process = (Process)sender;
                    Console.WriteLine("Exited: {0}", exited_process);
                    Console.WriteLine("Peak virtual memory usage: {0}", exited_process.PeakVirtualMemorySize64);
                    Console.WriteLine("Peak working set size: {0}", exited_process.PeakWorkingSet64);
                };

                Console.WriteLine(process);
                try {
                    process.EnableRaisingEvents = true;
                } catch {
                    Console.WriteLine("Failed to subscribe 'Exited' event: {0}", process);
                }                
            }
            Console.ReadLine();
        }
    }
}
408
06 апреля 2009 года
Lei fang
265 / / 01.10.2005
Чудеса да и только! C# покороче будет :)
Единственно что мне не ясно, почему когда я пытался обратиться к полям p.PeakVirtualMemorySize64 сразу же после завершения работы процесса, отписывало ошибку что процесс уже завершен и значение не доступно. Однако тут все отлично работает %) Событие Exited генерируется когда процесс еще не завершился или как?

The Exited event indicates that the associated process exited. This occurrence means either that the process terminated (aborted) or successfully closed. This event can occur only if the value of the EnableRaisingEvents property is true. В мсдн написано что когда завершился... м...

P.S. Код с внедрением длл сгодится на множество других целей :D Интересно поиграться
5
06 апреля 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: Lei fang
Единственно что мне не ясно, почему когда я пытался обратиться к полям p.PeakVirtualMemorySize64 сразу же после завершения работы процесса, отписывало ошибку что процесс уже завершен и значение не доступно. Однако тут все отлично работает %) Событие Exited генерируется когда процесс еще не завершился или как?

Сразу после завершения процесса делается финальный снимок параметров, который используется в контексте исполнения обработчика - вполне ожидаемое поведение. Думаю, что вне обработчика Exited, обращение к этим свойствам приведет к непредсказуемому результату.


Цитата: Lei fang
Код с внедрением длл сгодится на множество других целей :D

Это обычная техника (известна как dll injection), да только антивирусы будут немного озадачены таким поведением программы, могут ругаться.

З.Ы. Решение на .NET ограничено в возможностях - оно не позволяет обращаться к процессам-сервисам. Но так как вы запускаете процесс из собственного кода, ограничение вас не касается.

408
11 апреля 2009 года
Lei fang
265 / / 01.10.2005
Снова я здесь :D
Не могу поверить, но этот способ перестал для меня работать, опять ошибка "Process has exited, so the requested information is not available.", только в этот раз уже при исполнении делегата.
Раньше это работало, как только я прочитал ваш пост, через несколкьо дней решил оптимизировать, хоть по сути ничего и не поменял.
Вы можете мне объяснить почему в вашем случае при выполнении делегата нет ошибки, а в моем теперь есть? %) В упор не понимаю, логика-то одна
код таков:
Код:
private string[] ExecuteCompiledFile(string login, int max_exec_time_limit, int max_ram_usage_limit)
        {
            string[] ReturnValues = new string[3];
            bool delegate_executed = false;
                System.Diagnostics.ProcessStartInfo si = new System.Diagnostics.ProcessStartInfo();

                si.FileName = System.IO.Path.GetFullPath(cnfgtn.WorkFolder + "\\" + login + "\\testFile.exe");
                si.WorkingDirectory = cnfgtn.WorkFolder + "\\" + login;
                si.CreateNoWindow = true;
                si.UseShellExecute = false;

                System.Diagnostics.Process p = System.Diagnostics.Process.Start(si);
                p.Exited += delegate(object sender, System.EventArgs e)
                {
                    ReturnValues[2] = ((System.Diagnostics.Process)sender).PeakWorkingSet64.ToString(); //здесь вылетает исключение
                    delegate_executed = true;
                };
                p.EnableRaisingEvents = true;

                p.WaitForExit(max_exec_time_limit * 1000);

                if (!p.HasExited)
                {
                    ReturnValues[0] = "Test file has overused time limit (" + max_exec_time_limit + " seconds) and was terminated";
                    if (!p.HasExited)
                        p.Kill();
                }

                while (!delegate_executed) //это уже от безысходности, чтоб исключить случай когда следующий код выполнится до завершения работы делегата
                    continue;

                if (System.Convert.ToInt32(ReturnValues[2]) > max_ram_usage_limit)
                    ReturnValues[0] = "Test file has overused RAM limit (" + max_ram_usage_limit + " bytes) and was terminated";
                ReturnValues[1] = (p.ExitTime - p.StartTime).TotalSeconds.ToString();

                p.Close();

            return ReturnValues;
        }
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог