BOOL WINAPI EmptyWorkingSet( __in HANDLE hProcess );
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682606(v=vs.85).aspx
如此一來就可以減低一個程式所使用的記憶體, API怎麼使用就不是重點了。因為很簡單, 只要傳入想要reduce memory的PID就可以。雖然說minimem好用, 但手癢還是想自己寫一個windows service來達成這樣的功能, 所以就動手自己寫了一個(很久沒發程式文了...), 如果再加上UI的話, 就和minimem一模一樣了。
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <psapi.h>
#include <vector>
#include <string>
#pragma comment(lib, "Psapi.lib")
#define SERVICE_NAME L"Give Me More Memory"
#define LOG(x) x, __FUNCTION__, __LINE__
namespace {
TCHAR* serviceName = SERVICE_NAME;
SERVICE_STATUS serviceStatus = {0};
SERVICE_STATUS_HANDLE serviceStatusHandle = 0;
HANDLE stopServiceEvent = 0;
void TraceLog(const char* szMessage, const char* szFunctionName, const int nLineNum) {
char* szPath = "C:\\GiveMeMemory.log";
FILE* f = fopen(szPath, "a+");
if(f != NULL) {
fprintf(f, "[%s][%.4ld]\t\t>>> %s\n", szFunctionName, nLineNum, szMessage);
}
fclose(f);
}
}
void WINAPI ServiceControlHandler(DWORD controlCode);
void WINAPI ServiceMain(DWORD /*argc*/, TCHAR* /*argv*/[]);
void RunService();
void InstallService();
void UninstallService();
void EnumProcessID(std::vector<DWORD>& vecProcessID);
void ReduceWorkingSet(std::vector<DWORD>& vecProcessID);
void WINAPI ServiceControlHandler(DWORD controlCode)
{
switch(controlCode) {
case SERVICE_CONTROL_INTERROGATE:
break;
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
SetEvent(stopServiceEvent);
return;
case SERVICE_CONTROL_PAUSE:
break;
case SERVICE_CONTROL_CONTINUE:
break;
default:
if(controlCode >= 128 && controlCode <= 255)
// user defined control code
break;
else
// unrecognised control code
break;
}
SetServiceStatus(serviceStatusHandle, &serviceStatus);
}
void WINAPI ServiceMain( DWORD /*argc*/, TCHAR* /*argv*/[] )
{
// initialise service status
serviceStatus.dwServiceType = SERVICE_WIN32;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwWin32ExitCode = NO_ERROR;
serviceStatus.dwServiceSpecificExitCode = NO_ERROR;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
serviceStatusHandle = RegisterServiceCtrlHandler(serviceName, ServiceControlHandler);
stopServiceEvent = CreateEventW(0, 0, 0, L"Give Me Memory Service Event");
if(serviceStatusHandle)
{
// service is starting
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
SetServiceStatus( serviceStatusHandle, &serviceStatus );
// running
serviceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
serviceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
do
{
TraceLog(LOG("Loop--every 30 seconds will reduce process memory..."));
std::vector<DWORD> vecProcessID;
EnumProcessID(vecProcessID);
ReduceWorkingSet(vecProcessID);
}
while(WaitForSingleObject(stopServiceEvent, 30000) == WAIT_TIMEOUT);
// service was stopped
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus( serviceStatusHandle, &serviceStatus );
// do cleanup here
CloseHandle(stopServiceEvent);
stopServiceEvent = 0;
// service is now stopped
serviceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
serviceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus( serviceStatusHandle, &serviceStatus );
}
}
void RunService()
{
SERVICE_TABLE_ENTRY serviceTable[] = {
{ serviceName, ServiceMain },
{ 0, 0 }
};
BOOL bSetted = StartServiceCtrlDispatcher(serviceTable);
}
void InstallService()
{
SC_HANDLE serviceControlManager = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
if(serviceControlManager)
{
TCHAR path[_MAX_PATH + 1] = {0};
if(GetModuleFileName(0, path, sizeof(path)/sizeof(path[0])) > 0)
{
SC_HANDLE service = CreateService(serviceControlManager,
serviceName, serviceName,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, path,
0, 0, 0, 0, 0);
if(service) {
SERVICE_STATUS status = {0};
ControlService(service, SERVICE_CONTROL_CONTINUE, &status);
CloseServiceHandle(service);
}
}
CloseServiceHandle(serviceControlManager);
}
}
void UninstallService()
{
SC_HANDLE serviceControlManager = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
if(serviceControlManager)
{
SC_HANDLE service = OpenService(serviceControlManager,
serviceName, SERVICE_ALL_ACCESS);
if(service)
{
SERVICE_STATUS serviceStatus;
if(QueryServiceStatus(service, &serviceStatus))
{
if(serviceStatus.dwCurrentState == SERVICE_STOPPED)
DeleteService(service);
}
CloseServiceHandle(service);
}
CloseServiceHandle(serviceControlManager);
}
}
int _tmain(int argc, TCHAR* argv[])
{
if(argc > 1 && lstrcmpi(argv[1],TEXT("install")) == 0)
{
TraceLog(LOG("Install--Give Me More Memory Service..."));
InstallService();
}
else if(argc > 1 && lstrcmpi(argv[1], TEXT("uninstall")) == 0)
{
TraceLog(LOG("Uninstall--Give Me More Memory Service..."));
UninstallService();
}
else
{
// service manager will call this.
TraceLog(LOG("Start--Give Me More Memory Service..."));
RunService();
}
return 0;
}
void EnumProcessID(std::vector<DWORD>& vecProcessID) {
TraceLog(LOG("Enumerate--Enumerate process ID..."));
unsigned long nProcessNum = 100;
DWORD* dwProcesses = new DWORD[nProcessNum];
DWORD dwNeeded = 0, dwTotalProcesses = 0;
while(true) {
if (!EnumProcesses(dwProcesses, sizeof(DWORD)*nProcessNum, &dwNeeded )) {
return;
}
dwTotalProcesses = dwNeeded / sizeof(DWORD);
if(nProcessNum > dwTotalProcesses) {
break;
} else {
nProcessNum *= 2;
delete[] dwProcesses;
dwProcesses = new DWORD[nProcessNum];
}
}
// Print the name and process identifier for each process.
for (unsigned int i = 0; i < dwTotalProcesses; i++ )
{
vecProcessID.push_back(dwProcesses[i]);
}
delete[] dwProcesses;
}
void ReduceWorkingSet(std::vector<DWORD>& vecProcessID)
{
// Get a handle to the process.
TraceLog(LOG("Reduce--Reduce process memory..."));
std::vector<DWORD>::iterator iter = vecProcessID.begin();
for (; iter != vecProcessID.end(); ++iter)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_SET_QUOTA, FALSE, *iter);
BOOL bRet = EmptyWorkingSet(hProcess);
CloseHandle(hProcess);
}
}
有興趣的人就自己動手寫寫看吧, 這個程式也順便有windows service的功能了, 使用方法可以參考main function裡的參數。
沒有留言:
張貼留言