3

Based on the following link: MSDN Docu

I am trying to get the size of the page file that is currently being used.

Here's how I am getting the values:

ActualPageFileSize = ullAvailPageFile - ullTotalPageFile
AvailablePageFileSize = ullAvailPageFile - ullAvailPhys
UsedPageFile = ActualPageFileSize - AvailablePageFileSize

Above computation is based on another post: Another post

The issue that I am having right now is that sometimes the value of AvailablePageFileSize is greater than the value of ActualPageFileSize, hence returning a negative value for the UsedPageFile.

Have any of you encountered this? Any idea will be greatly appreciated.

Thank you in advance!

P.S.

Sample code:

#define DIV 1024

void _tmain()
{
  MEMORYSTATUSEX statex;

  statex.dwLength = sizeof (statex);

  GlobalMemoryStatusEx (&statex);

    double committedBytes = 1;

    _tprintf (TEXT("==================================================\n"));
    _tprintf (TEXT("GlobalMemoryStatusEx\n"));
    _tprintf (TEXT("==================================================\n"));
    _tprintf (TEXT("           %PhysUsed : %ld\n"), statex.dwMemoryLoad);
    _tprintf (TEXT("        ullTotalPhys : %I64d (%I64d MB)\n"), statex.ullTotalPhys, statex.ullTotalPhys / (DIV*DIV));
    _tprintf (TEXT("        ullAvailPhys : %I64d (%I64d MB)\n"), statex.ullAvailPhys, statex.ullAvailPhys / (DIV*DIV));
    _tprintf (TEXT("         ullUsedPhys : %I64d (%I64d MB)\n"), statex.ullTotalPhys - statex.ullAvailPhys, (statex.ullTotalPhys - statex.ullAvailPhys) / (DIV*DIV));
    _tprintf (TEXT("                       --------------------------\n"));
    _tprintf (TEXT("   Phys Avail + Used = %I64d (%I64d MB)\n"), statex.ullAvailPhys + (statex.ullTotalPhys - statex.ullAvailPhys), (statex.ullAvailPhys + (statex.ullTotalPhys - statex.ullAvailPhys)) / (DIV*DIV));

    _tprintf (TEXT("==================================================\n"));
    _tprintf (TEXT("    ullTotalPageFile : %I64d (%I64d MB)\n"), statex.ullTotalPageFile, statex.ullTotalPageFile / (DIV*DIV));
    _tprintf (TEXT("    ullAvailPageFile : %I64d (%I64d MB)\n"), statex.ullAvailPageFile, statex.ullAvailPageFile / (DIV*DIV));
    _tprintf (TEXT("     ullUsedPageFile : %I64d (%I64d MB)\n"), statex.ullTotalPageFile - statex.ullAvailPageFile, (statex.ullTotalPageFile - statex.ullAvailPageFile) / (DIV*DIV));
    _tprintf (TEXT("                       --------------------------\n"));
    _tprintf (TEXT("   Page Avail + Used = %I64d (%I64d MB)\n"), statex.ullAvailPageFile + (statex.ullTotalPageFile - statex.ullAvailPageFile), (statex.ullAvailPageFile + (statex.ullTotalPageFile - statex.ullAvailPageFile)) / (DIV*DIV));

    _tprintf (TEXT("==================================================\n"));
    _tprintf (TEXT(" ActualTotalPageFile : %I64d (%I64d MB)\n"), statex.ullTotalPageFile - statex.ullTotalPhys, (statex.ullTotalPageFile - statex.ullTotalPhys) / (DIV*DIV));
    _tprintf (TEXT(" ActualAvailPageFile : %I64d (%I64d MB)\n"), statex.ullAvailPageFile - statex.ullAvailPhys, (statex.ullAvailPageFile - statex.ullAvailPhys) / (DIV*DIV));
    _tprintf (TEXT("  ActualPageFileUsed : %I64d (%I64d MB)\n"), (statex.ullTotalPageFile - statex.ullTotalPhys) - (statex.ullAvailPageFile - statex.ullAvailPhys), ((statex.ullTotalPageFile - statex.ullTotalPhys) - (statex.ullAvailPageFile - statex.ullAvailPhys)) / (DIV*DIV));
    _tprintf (TEXT("            Variance : %I64d (%I64d MB)\n"), (statex.ullAvailPageFile - statex.ullAvailPhys) - (statex.ullTotalPageFile - statex.ullTotalPhys), ((statex.ullAvailPageFile - statex.ullAvailPhys) - (statex.ullTotalPageFile - statex.ullTotalPhys)) / (DIV*DIV));
    _tprintf (TEXT("                       --------------------------\n"));
    _tprintf (TEXT("ActPage Avail + Used = %I64d (%I64d MB)\n"), (statex.ullAvailPageFile - statex.ullAvailPhys) + ((statex.ullTotalPageFile - statex.ullTotalPhys) - (statex.ullAvailPageFile - statex.ullAvailPhys)), ((statex.ullAvailPageFile - statex.ullAvailPhys) + ((statex.ullTotalPageFile - statex.ullTotalPhys) - (statex.ullAvailPageFile - statex.ullAvailPhys))) / (DIV*DIV));
    _tprintf (TEXT("==================================================\n"));
    _tprintf (TEXT("     ullTotalVirtual : %I64d (%I64d MB)\n"), statex.ullTotalVirtual, statex.ullTotalVirtual / (DIV*DIV));
    _tprintf (TEXT("     ullAvailVirtual : %I64d (%I64d MB)\n"), statex.ullAvailVirtual, statex.ullAvailVirtual / (DIV*DIV));
    _tprintf (TEXT(" ullAvailVirtualUsed : %I64d (%I64d MB)\n"), statex.ullTotalVirtual - statex.ullAvailVirtual, (statex.ullTotalVirtual - statex.ullAvailVirtual) / (DIV*DIV));


    PERFORMACE_INFORMATION perfInfo;
    int ret;

    ret = GetPerformanceInfo (&perfInfo,sizeof(perfInfo));

    _tprintf (TEXT("==================================================\n"));
    _tprintf (TEXT("GetPerformanceInfo\n"));
    _tprintf (TEXT("==================================================\n"));

    _tprintf (TEXT("       PageSize : %d (%d MB) \n"), perfInfo.PageSize, perfInfo.PageSize / DIV);
    _tprintf (TEXT("    CommitTotal : %d (%d MB) X %d = %I64d (%I64d MB)\n"), perfInfo.CommitTotal, perfInfo.CommitTotal / DIV, perfInfo.PageSize, (DWORDLONG)perfInfo.CommitTotal * perfInfo.PageSize, (DWORDLONG)(perfInfo.CommitTotal * perfInfo.PageSize)  / (DIV*DIV));
    _tprintf (TEXT("    CommitLimit : %d (%d MB) X %d = %I64d (%I64d MB)\n"), perfInfo.CommitLimit, perfInfo.CommitLimit / DIV, perfInfo.PageSize, (DWORDLONG)perfInfo.CommitLimit * perfInfo.PageSize, (DWORDLONG)(perfInfo.CommitLimit * perfInfo.PageSize) / (DIV*DIV));
    _tprintf (TEXT("    CommitAvail : %d (%d MB) X %d = %I64d (%I64d MB)\n"), perfInfo.CommitLimit - perfInfo.CommitTotal, (perfInfo.CommitLimit - perfInfo.CommitTotal) / DIV, perfInfo.PageSize, (DWORDLONG)(perfInfo.CommitLimit - perfInfo.CommitTotal) * perfInfo.PageSize, (DWORDLONG)((perfInfo.CommitLimit - perfInfo.CommitTotal) * perfInfo.PageSize) / (DIV*DIV));
    _tprintf (TEXT("  PhysicalTotal : %d (%d MB) X %d = %I64d (%I64d MB)\n"), perfInfo.PhysicalTotal, perfInfo.PhysicalTotal / DIV, perfInfo.PageSize, (DWORDLONG)perfInfo.PhysicalTotal * perfInfo.PageSize, (DWORDLONG)(perfInfo.PhysicalTotal * perfInfo.PageSize) / (DIV*DIV));
    _tprintf (TEXT("  PhysicalAvail : %d (%d MB) X %d = %I64d (%I64d MB)\n"), perfInfo.PhysicalAvailable, perfInfo.PhysicalAvailable / DIV, perfInfo.PageSize, (DWORDLONG)(perfInfo.PhysicalAvailable * perfInfo.PageSize), (DWORDLONG)(perfInfo.PhysicalAvailable * perfInfo.PageSize) / (DIV*DIV));

    DWORDLONG ptotal = (DWORDLONG)(perfInfo.CommitLimit - perfInfo.PhysicalTotal) * perfInfo.PageSize;
    DWORDLONG pavail = (DWORDLONG)((perfInfo.CommitLimit - perfInfo.CommitTotal) - perfInfo.PhysicalAvailable) * perfInfo.PageSize;
    _tprintf (TEXT("\nCommitLimit - PhysicalTotal = %I64d (%I64d MB) \n"), ptotal, (DWORDLONG)ptotal / (DIV*DIV));
    _tprintf (TEXT("CommitAvail - PhysicalAvail = %I64d (%I64d MB) \n"), pavail, (DWORDLONG)pavail / (DIV*DIV));
    _tprintf (TEXT("CommitUsed  - %I64d (%I64d MB) \n"), (DWORDLONG)(ptotal - pavail), (DWORDLONG)(ptotal - pavail) / (DIV*DIV));
}

Sample Good Output:

R:\>memtest.exe
==================================================
GlobalMemoryStatusEx
==================================================
           PhysUsed : 24
        ullTotalPhys : 4294430720 (4095 MB)
        ullAvailPhys : 3231776768 (3082 MB)
         ullUsedPhys : 1062653952 (1013 MB)
                       --------------------------
   Phys Avail + Used = 4294430720 (4095 MB)
==================================================
    ullTotalPageFile : 5032628224 (4799 MB)
    ullAvailPageFile : 3932905472 (3750 MB)
     ullUsedPageFile : 1099722752 (1048 MB)
                       --------------------------
   Page Avail + Used = 5032628224 (4799 MB)
==================================================
 ActualTotalPageFile : 738197504 (704 MB)
 ActualAvailPageFile : 701128704 (668 MB)
  ActualPageFileUsed : 37068800 (35 MB)
            Variance : -37068800 (17592186044380 MB)
                       --------------------------
ActPage Avail + Used = 738197504 (704 MB)
==================================================
     ullTotalVirtual : 2147352576 (2047 MB)
     ullAvailVirtual : 2072608768 (1976 MB)
 ullAvailVirtualUsed : 74743808 (71 MB)
==================================================
GetPerformanceInfo
==================================================
       PageSize : 4096 (4 MB)
    CommitTotal : 268487 (262 MB) X 4096 = 1099722752 (1048 MB)
    CommitLimit : 1228669 (1199 MB) X 4096 = 5032628224 (703 MB)
    CommitAvail : 960182 (937 MB) X 4096 = 3932905472 (3750 MB)
  PhysicalTotal : 1048445 (1023 MB) X 4096 = 4294430720 (4095 MB)
  PhysicalAvail : 789000 (770 MB) X 4096 = 3231744000 (3082 MB)

CommitLimit - PhysicalTotal = 738197504 (704 MB)
CommitAvail - PhysicalAvail = 701161472 (668 MB)
CommitUsed  - 37036032 (35 MB)

R:\>

Sample Bad Output:

U:\>memtest.exe
==================================================
GlobalMemoryStatusEx
==================================================
           PhysUsed : 35
        ullTotalPhys : 3220688896 (3071 MB)
        ullAvailPhys : 2087751680 (1991 MB) <--- Should be less than ullAvailPageFile
         ullUsedPhys : 1132937216 (1080 MB)
                       --------------------------
   Phys Avail + Used = 3220688896 (3071 MB)
==================================================
    ullTotalPageFile : 3757559808 (3583 MB)
    ullAvailPageFile : 1925316608 (1836 MB) <-- Shouldbe greater than ullAvailPhys
     ullUsedPageFile : 1832243200 (1747 MB)
                       --------------------------
   Page Avail + Used = 3757559808 (3583 MB)
==================================================
 ActualTotalPageFile : 536870912 (512 MB)
 ActualAvailPageFile : -162435072 (17592186044261 MB) <-- This is ullAvailPageFile - ullAvailPhys
  ActualPageFileUsed : 699305984 (666 MB)
            Variance : -699305984 (17592186043749 MB)
                       --------------------------
ActPage Avail + Used = 536870912 (512 MB)
==================================================
     ullTotalVirtual : 2147352576 (2047 MB)
     ullAvailVirtual : 2139230208 (2040 MB)
 ullAvailVirtualUsed : 8122368 (7 MB)
==================================================
GetPerformanceInfo
==================================================
       PageSize : 4096 (4 MB)
    CommitTotal : 447325 (436 MB) X 4096 = 1832243200 (1747 MB)
    CommitLimit : 917373 (895 MB) X 4096 = 3757559808 (3583 MB)
    CommitAvail : 470048 (459 MB) X 4096 = 1925316608 (1836 MB)
  PhysicalTotal : 786301 (767 MB) X 4096 = 3220688896 (3071 MB)
  PhysicalAvail : 509698 (497 MB) X 4096 = 2087723008 (1991 MB)

CommitLimit - PhysicalTotal = 536870912 (512 MB)
CommitAvail - PhysicalAvail = 17592023638016 (16777061 MB)
CommitUsed  - -17591486767104 (17592169267866 MB)

U:\>
vlxdxmxr
  • 33
  • 4
  • There's a *help* link at the top right in the question and answer editor. It explains the markdown editing facilities. Read it and fix your formatting. Also, providing a [mcve] is highly recommended. – IInspectable Jun 20 '17 at 09:46
  • The "should be" assertions are simply not correct. Paging file size is subject to configuration and dynamically changes as the need for committed memory changes. Russinovich's "Windows Internals" is required reading if you want to divine the meaning of these numbers. Use performance counters or WMI to get actual paging file and memory usage statistics, play with Perfmon.exe to see them. – Hans Passant Jun 20 '17 at 10:34
  • if you want get the information of paged files in system - call `NtQuerySystemInformation(SystemPageFileInformation,..` - and you got complete information about this [`SYSTEM_PAGEFILE_INFORMATION`](http://processhacker.sourceforge.net/doc/ntexapi_8h_source.html#l01643) – RbMm Jun 20 '17 at 10:36
  • @Hans Passant if you subtract the ullTotalPhys from ullTotalPageFile, you get the actual page file size as configured in the system. WMI returns the same value. Also the physical memory side of things are correct as confirmed based on resmon and perfmon. I get that these values change, but the values that I compute are results of one winapi call. As you can see the calls to GlobalMemoryStatusEx and GetPerformanceInfo return values that are similar. – vlxdxmxr Jun 20 '17 at 12:44
  • @RbMm I will​ try to implement this code revert back with results. Thanks – vlxdxmxr Jun 20 '17 at 12:45
  • @vlxdxmxr - code is very simply and work from win2000 up to win10. if want can paste it – RbMm Jun 20 '17 at 12:54
  • @RbMm please do so. Quick pass through the documentation, it says that it may be deprecated in the future. My company's application need to support this feature beyond win10 so there's that. – vlxdxmxr Jun 20 '17 at 14:52

1 Answers1

0

the next code worked how minimum from win2000 up to the latest win10 x64. about deprecated, undocumented, etc:

NtQuerySystemInformation may be altered or unavailable in future versions of Windows.

i read this already ~15 years. are ntdll api will be/can be removed in future - my personal option that no. never. this is base native api and all so called win32 api based on this. but this is only my option. how minimum just now this is fine worked on all existing windows versions. as is (i sure that will be worked and on new builds too)

typedef struct SYSTEM_PAGEFILE_INFORMATION
{
    ULONG NextEntryOffset;
    ULONG TotalSize;
    ULONG TotalInUse;
    ULONG PeakUsage;
    UNICODE_STRING PageFileName;
} *PSYSTEM_PAGEFILE_INFORMATION;

NTSTATUS GetPageFilesInfo()
{
    static volatile UCHAR guz;
    PVOID stack = alloca(guz);
    ULONG cb = 0, rcb = 2*sizeof(SYSTEM_PAGEFILE_INFORMATION) + 64* sizeof(WCHAR);

    union {
        PVOID buf;
        PSYSTEM_PAGEFILE_INFORMATION pspfi;
        PBYTE pb;
    };
    NTSTATUS status;
    do 
    {
        if (cb < rcb)
        {
            cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
        }

        if (0 <= (status = NtQuerySystemInformation(SystemPageFileInformation, buf, cb, &rcb)))
        {
            ULONG NextEntryOffset = 0;
            do 
            {
                pb += NextEntryOffset;

                DbgPrint("%ukb %ukb %ukb %wZ\n", pspfi->TotalInUse, pspfi->PeakUsage, pspfi->TotalSize, &pspfi->PageFileName);

            } while (NextEntryOffset = pspfi->NextEntryOffset);

            break;
        }

    } while (status == STATUS_INFO_LENGTH_MISMATCH);

    return status;
}

funny that if open page for ZwQuerySystemInformation

[ZwQuerySystemInformation is no longer available for use as of Windows 8. Instead, use the alternate functions listed in this topic.]

but this is direct lie - ZwQuerySystemInformation available and in win 8, win 8.1, win 10.. and in user mode Zw and Nt functions - this is aliases - it always point to same address (this is single function with 2 names)

RbMm
  • 31,280
  • 3
  • 35
  • 56