├── .github └── FUNDING.yml ├── LICENSE ├── README.md ├── graph.png ├── preview.png ├── screen.png └── source ├── MemCleaner.c └── psapi.h /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: ['https://kay-software.ru/content/donate'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 DosX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MemCleaner 2 | A simple memory cleanup utility in C for Windows that enumerates all processes at 40 millisecond intervals and applies an ```EmptyWorkingSet``` for each one (freeing unused memory). 3 | 4 | ### [Download compiled as .EXE](https://github.com/DosX-dev/MemCleaner/releases/tag/Builds) 5 | 6 | ![](screen.png) 7 | ![](graph.png) 8 | -------------------------------------------------------------------------------- /graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DosX-dev/MemCleaner/6463a9b9d941323ee6b113407f853f2b31570fb9/graph.png -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DosX-dev/MemCleaner/6463a9b9d941323ee6b113407f853f2b31570fb9/preview.png -------------------------------------------------------------------------------- /screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DosX-dev/MemCleaner/6463a9b9d941323ee6b113407f853f2b31570fb9/screen.png -------------------------------------------------------------------------------- /source/MemCleaner.c: -------------------------------------------------------------------------------- 1 | // Coded by DosX 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "psapi.h" 8 | 9 | #define true 0b1 10 | #define false 0b0 11 | 12 | #define GLOBAL_LOOP_DELAY 60000 // 60 seconds 13 | #define PROCESSES_LOOP_DELAY 40 // 40 milliseconds 14 | 15 | char *getFileNameFromPath(char *path) { // Extract the file name from a given path 16 | for (size_t i = strlen(path) - 1; i; i--) { 17 | if (path[i] == '\\') 18 | return &path[i + 1]; 19 | } 20 | return path; 21 | } 22 | 23 | int getFreeMemory() { 24 | MEMORYSTATUSEX memInfo; 25 | memInfo.dwLength = sizeof(memInfo); 26 | 27 | GlobalMemoryStatusEx(&memInfo); 28 | 29 | // ULONGLONG totalPhysicalMemory = memInfo.ullTotalPhys; 30 | // ULONGLONG usedPhysicalMemory = totalPhysicalMemory - memInfo.ullAvailPhys; 31 | ULONGLONG freePhysicalMemory = memInfo.ullAvailPhys; 32 | 33 | return freePhysicalMemory / (1024 * 1024); 34 | } 35 | 36 | void main() { 37 | SetConsoleTitle("MemCleaner by DosX-dev (GitHub)"); 38 | 39 | bool createdNew; 40 | 41 | // Create a mutex to ensure only one instance of the program runs 42 | HANDLE mutex = CreateMutex(NULL, TRUE, "memcleaner"); 43 | if (GetLastError() == ERROR_ALREADY_EXISTS) { 44 | exit(0x00); // Exit if another instance is already running 45 | } 46 | 47 | while (true) { // Continuous loop to clean memory and wait 48 | int freeMemoryBefore = getFreeMemory(); 49 | 50 | DWORD processIds[1024], cbNeeded, cProcesses; 51 | unsigned int i; 52 | HANDLE hProcess; 53 | 54 | if (!EnumProcesses(processIds, sizeof(processIds), &cbNeeded)) { // Enumerate all running processes 55 | return; 56 | } 57 | 58 | cProcesses = cbNeeded / sizeof(DWORD); 59 | for (i = 0; i < cProcesses; i++) { 60 | if (processIds[i] != 0) { 61 | hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processIds[i]); // Open the process 62 | 63 | if (hProcess != NULL) { 64 | if (hProcess) { 65 | char pathbuf[MAX_PATH]; 66 | 67 | if (GetModuleFileNameEx(hProcess, NULL, pathbuf, MAX_PATH)) { 68 | EmptyWorkingSet(hProcess); // Clean the memory of a specific process 69 | CloseHandle(hProcess); // Close the handle 70 | 71 | Sleep(PROCESSES_LOOP_DELAY); 72 | 73 | printf("Memory cleaned for: %s [%i]\n", getFileNameFromPath(pathbuf), (int)hProcess); 74 | } 75 | } 76 | } 77 | } 78 | } 79 | printf("\nMemory cleaned: %d MB\nNext cycle in %d seconds.\n", getFreeMemory() - freeMemoryBefore, GLOBAL_LOOP_DELAY / 1000); 80 | 81 | Sleep(GLOBAL_LOOP_DELAY); 82 | } 83 | 84 | CloseHandle(mutex); 85 | } 86 | -------------------------------------------------------------------------------- /source/psapi.h: -------------------------------------------------------------------------------- 1 | /** 2 | * This file has no copyright assigned and is placed in the Public Domain. 3 | * This file is part of the w64 mingw-runtime package. 4 | * No warranty is given; refer to the file DISCLAIMER within this package. 5 | */ 6 | #ifndef _PSAPI_H_ 7 | #define _PSAPI_H_ 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | #ifdef UNICODE 14 | #define GetModuleBaseName GetModuleBaseNameW 15 | #define GetModuleFileNameEx GetModuleFileNameExW 16 | #define GetMappedFileName GetMappedFileNameW 17 | #define GetDeviceDriverBaseName GetDeviceDriverBaseNameW 18 | #define GetDeviceDriverFileName GetDeviceDriverFileNameW 19 | #define PENUM_PAGE_FILE_CALLBACK PENUM_PAGE_FILE_CALLBACKW 20 | #define EnumPageFiles EnumPageFilesW 21 | #define GetProcessImageFileName GetProcessImageFileNameW 22 | #else 23 | #define GetModuleBaseName GetModuleBaseNameA 24 | #define GetModuleFileNameEx GetModuleFileNameExA 25 | #define GetMappedFileName GetMappedFileNameA 26 | #define GetDeviceDriverBaseName GetDeviceDriverBaseNameA 27 | #define GetDeviceDriverFileName GetDeviceDriverFileNameA 28 | #define PENUM_PAGE_FILE_CALLBACK PENUM_PAGE_FILE_CALLBACKA 29 | #define EnumPageFiles EnumPageFilesA 30 | #define GetProcessImageFileName GetProcessImageFileNameA 31 | #endif 32 | 33 | WINBOOL WINAPI EnumProcesses(DWORD *lpidProcess,DWORD cb,DWORD *cbNeeded); 34 | WINBOOL WINAPI EnumProcessModules(HANDLE hProcess,HMODULE *lphModule,DWORD cb,LPDWORD lpcbNeeded); 35 | DWORD WINAPI GetModuleBaseNameA(HANDLE hProcess,HMODULE hModule,LPSTR lpBaseName,DWORD nSize); 36 | DWORD WINAPI GetModuleBaseNameW(HANDLE hProcess,HMODULE hModule,LPWSTR lpBaseName,DWORD nSize); 37 | DWORD WINAPI GetModuleFileNameExA(HANDLE hProcess,HMODULE hModule,LPSTR lpFilename,DWORD nSize); 38 | DWORD WINAPI GetModuleFileNameExW(HANDLE hProcess,HMODULE hModule,LPWSTR lpFilename,DWORD nSize); 39 | 40 | typedef struct _MODULEINFO { 41 | LPVOID lpBaseOfDll; 42 | DWORD SizeOfImage; 43 | LPVOID EntryPoint; 44 | } MODULEINFO,*LPMODULEINFO; 45 | 46 | WINBOOL WINAPI GetModuleInformation(HANDLE hProcess,HMODULE hModule,LPMODULEINFO lpmodinfo,DWORD cb); 47 | WINBOOL WINAPI EmptyWorkingSet(HANDLE hProcess); 48 | WINBOOL WINAPI QueryWorkingSet(HANDLE hProcess,PVOID pv,DWORD cb); 49 | WINBOOL WINAPI QueryWorkingSetEx(HANDLE hProcess,PVOID pv,DWORD cb); 50 | WINBOOL WINAPI InitializeProcessForWsWatch(HANDLE hProcess); 51 | 52 | typedef struct _PSAPI_WS_WATCH_INFORMATION { 53 | LPVOID FaultingPc; 54 | LPVOID FaultingVa; 55 | } PSAPI_WS_WATCH_INFORMATION,*PPSAPI_WS_WATCH_INFORMATION; 56 | 57 | WINBOOL WINAPI GetWsChanges(HANDLE hProcess,PPSAPI_WS_WATCH_INFORMATION lpWatchInfo,DWORD cb); 58 | DWORD WINAPI GetMappedFileNameW(HANDLE hProcess,LPVOID lpv,LPWSTR lpFilename,DWORD nSize); 59 | DWORD WINAPI GetMappedFileNameA(HANDLE hProcess,LPVOID lpv,LPSTR lpFilename,DWORD nSize); 60 | WINBOOL WINAPI EnumDeviceDrivers(LPVOID *lpImageBase,DWORD cb,LPDWORD lpcbNeeded); 61 | DWORD WINAPI GetDeviceDriverBaseNameA(LPVOID ImageBase,LPSTR lpBaseName,DWORD nSize); 62 | DWORD WINAPI GetDeviceDriverBaseNameW(LPVOID ImageBase,LPWSTR lpBaseName,DWORD nSize); 63 | DWORD WINAPI GetDeviceDriverFileNameA(LPVOID ImageBase,LPSTR lpFilename,DWORD nSize); 64 | DWORD WINAPI GetDeviceDriverFileNameW(LPVOID ImageBase,LPWSTR lpFilename,DWORD nSize); 65 | 66 | typedef struct _PROCESS_MEMORY_COUNTERS { 67 | DWORD cb; 68 | DWORD PageFaultCount; 69 | SIZE_T PeakWorkingSetSize; 70 | SIZE_T WorkingSetSize; 71 | SIZE_T QuotaPeakPagedPoolUsage; 72 | SIZE_T QuotaPagedPoolUsage; 73 | SIZE_T QuotaPeakNonPagedPoolUsage; 74 | SIZE_T QuotaNonPagedPoolUsage; 75 | SIZE_T PagefileUsage; 76 | SIZE_T PeakPagefileUsage; 77 | } PROCESS_MEMORY_COUNTERS; 78 | typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS; 79 | 80 | typedef struct _PROCESS_MEMORY_COUNTERS_EX { 81 | DWORD cb; 82 | DWORD PageFaultCount; 83 | SIZE_T PeakWorkingSetSize; 84 | SIZE_T WorkingSetSize; 85 | SIZE_T QuotaPeakPagedPoolUsage; 86 | SIZE_T QuotaPagedPoolUsage; 87 | SIZE_T QuotaPeakNonPagedPoolUsage; 88 | SIZE_T QuotaNonPagedPoolUsage; 89 | SIZE_T PagefileUsage; 90 | SIZE_T PeakPagefileUsage; 91 | SIZE_T PrivateUsage; 92 | } PROCESS_MEMORY_COUNTERS_EX; 93 | typedef PROCESS_MEMORY_COUNTERS_EX *PPROCESS_MEMORY_COUNTERS_EX; 94 | 95 | WINBOOL WINAPI GetProcessMemoryInfo(HANDLE Process,PPROCESS_MEMORY_COUNTERS ppsmemCounters,DWORD cb); 96 | 97 | typedef struct _PERFORMANCE_INFORMATION { 98 | DWORD cb; 99 | SIZE_T CommitTotal; 100 | SIZE_T CommitLimit; 101 | SIZE_T CommitPeak; 102 | SIZE_T PhysicalTotal; 103 | SIZE_T PhysicalAvailable; 104 | SIZE_T SystemCache; 105 | SIZE_T KernelTotal; 106 | SIZE_T KernelPaged; 107 | SIZE_T KernelNonpaged; 108 | SIZE_T PageSize; 109 | DWORD HandleCount; 110 | DWORD ProcessCount; 111 | DWORD ThreadCount; 112 | } PERFORMANCE_INFORMATION,*PPERFORMANCE_INFORMATION,PERFORMACE_INFORMATION,*PPERFORMACE_INFORMATION; 113 | 114 | WINBOOL WINAPI GetPerformanceInfo (PPERFORMACE_INFORMATION pPerformanceInformation,DWORD cb); 115 | 116 | typedef struct _ENUM_PAGE_FILE_INFORMATION { 117 | DWORD cb; 118 | DWORD Reserved; 119 | SIZE_T TotalSize; 120 | SIZE_T TotalInUse; 121 | SIZE_T PeakUsage; 122 | } ENUM_PAGE_FILE_INFORMATION,*PENUM_PAGE_FILE_INFORMATION; 123 | 124 | typedef WINBOOL (*PENUM_PAGE_FILE_CALLBACKW) (LPVOID pContext,PENUM_PAGE_FILE_INFORMATION pPageFileInfo,LPCWSTR lpFilename); 125 | typedef WINBOOL (*PENUM_PAGE_FILE_CALLBACKA) (LPVOID pContext,PENUM_PAGE_FILE_INFORMATION pPageFileInfo,LPCSTR lpFilename); 126 | 127 | WINBOOL WINAPI EnumPageFilesW (PENUM_PAGE_FILE_CALLBACKW pCallBackRoutine,LPVOID pContext); 128 | WINBOOL WINAPI EnumPageFilesA (PENUM_PAGE_FILE_CALLBACKA pCallBackRoutine,LPVOID pContext); 129 | DWORD WINAPI GetProcessImageFileNameA(HANDLE hProcess,LPSTR lpImageFileName,DWORD nSize); 130 | DWORD WINAPI GetProcessImageFileNameW(HANDLE hProcess,LPWSTR lpImageFileName,DWORD nSize); 131 | 132 | #ifdef __cplusplus 133 | } 134 | #endif 135 | #endif 136 | --------------------------------------------------------------------------------