The Windows implementation of getMemoryInfo() appears to have a calculation error.
|
uint64_t WinSystemInfo::getMemoryInfo(memory_info_t type) const { |
|
MEMORYSTATUSEX info; |
|
|
|
info.dwLength = sizeof(MEMORYSTATUSEX); |
|
GlobalMemoryStatusEx(&info); |
|
|
|
switch (type) { |
|
case MEM_INFO_TOTAL: return (uint64_t)info.ullTotalPhys; |
|
case MEM_INFO_FREE: return (uint64_t)info.ullAvailPhys; |
|
case MEM_INFO_SWAP: return (uint64_t)info.ullAvailPageFile; |
|
case MEM_INFO_USABLE: |
|
return (uint64_t)(info.ullAvailPhys + info.ullAvailPageFile); |
|
} |
|
|
|
return 0; |
|
} |
In getUsableMemory(), the code sums ullAvailPhys + ullAvailPageFile. However, according to the Windows API documentation, ullAvailPageFile already includes both free RAM and available pagefile space ("The maximum amount of memory the current process can commit ...": https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-memorystatusex). This causes the free RAM to be counted twice.
Similarly, getFreeSwapMemory() returns ullAvailPageFile directly, which includes free physical RAM instead of showing only the isolated swap space.
Suggested fix:
MEM_INFO_USABLE: Should just return info.ullAvailPageFile. Note that this represents the unallocated system commit limit (free RAM + free swap), which differs fundamentally from Linux's MemAvailable. It is impossible to calculate a true MemAvailable equivalent using only the MEMORYSTATUSEX structure; achieving that requires switching to PERFORMANCE_INFORMATION and calculating it via perfInfo.PhysicalAvailable * perfInfo.PageSize (which includes the system cache/standby list: https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-performance_information), as done in Python's psutil:
unsigned long long totalPhys, availPhys, totalSys, availSys, pageSize;
PERFORMANCE_INFORMATION perfInfo;
if (!GetPerformanceInfo(&perfInfo, sizeof(PERFORMANCE_INFORMATION))) {
psutil_oserror();
return NULL;
}
// values are size_t, widen (if needed) to long long
pageSize = perfInfo.PageSize;
totalPhys = perfInfo.PhysicalTotal * pageSize;
availPhys = perfInfo.PhysicalAvailable * pageSize;
totalSys = perfInfo.CommitLimit * pageSize;
availSys = totalSys - perfInfo.CommitTotal * pageSize;
https://github.com/giampaolo/psutil/blob/v7.2.2/psutil/arch/windows/mem.c#L23-L39
MEM_INFO_SWAP should return info.ullAvailPageFile - info.ullAvailPhys to isolate the pagefile, which is roughly equivalent to Linux's SwapFree in /proc/meminfo.
Here is how Zabbix does it (it separates total swap and available swap):
ms_ex.dwLength = sizeof(MEMORYSTATUSEX);
(*zbx_get_GlobalMemoryStatusEx())(&ms_ex);
real_swap_total = ms_ex.ullTotalPageFile > ms_ex.ullTotalPhys ?
ms_ex.ullTotalPageFile - ms_ex.ullTotalPhys : 0;
real_swap_avail = ms_ex.ullAvailPageFile > ms_ex.ullAvailPhys ?
ms_ex.ullAvailPageFile - ms_ex.ullAvailPhys : 0;
https://github.com/zabbix/zabbix/blob/7.4.11/src/libs/zbxsysinfo/win32/swap.c#L130-L137
Note: this issue and its proposed fix were generated with help from Gemini and require manual review.
The Windows implementation of
getMemoryInfo()appears to have a calculation error.cbang/src/cbang/os/win/WinSystemInfo.cpp
Lines 68 to 83 in f6386fd
In
getUsableMemory(), the code sumsullAvailPhys + ullAvailPageFile. However, according to the Windows API documentation,ullAvailPageFilealready includes both free RAM and available pagefile space ("The maximum amount of memory the current process can commit ...": https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-memorystatusex). This causes the free RAM to be counted twice.Similarly,
getFreeSwapMemory()returnsullAvailPageFiledirectly, which includes free physical RAM instead of showing only the isolated swap space.Suggested fix:
MEM_INFO_USABLE: Should just returninfo.ullAvailPageFile. Note that this represents the unallocated system commit limit (free RAM + free swap), which differs fundamentally from Linux'sMemAvailable. It is impossible to calculate a trueMemAvailableequivalent using only theMEMORYSTATUSEXstructure; achieving that requires switching toPERFORMANCE_INFORMATIONand calculating it viaperfInfo.PhysicalAvailable * perfInfo.PageSize(which includes the system cache/standby list: https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-performance_information), as done in Python'spsutil:https://github.com/giampaolo/psutil/blob/v7.2.2/psutil/arch/windows/mem.c#L23-L39
MEM_INFO_SWAPshould returninfo.ullAvailPageFile - info.ullAvailPhysto isolate the pagefile, which is roughly equivalent to Linux'sSwapFreein/proc/meminfo.Here is how Zabbix does it (it separates total swap and available swap):
https://github.com/zabbix/zabbix/blob/7.4.11/src/libs/zbxsysinfo/win32/swap.c#L130-L137
Note: this issue and its proposed fix were generated with help from Gemini and require manual review.