解释一行二进制补码数学计数空闲虚拟内存

发布于 2024-09-30 02:48:55 字数 2801 浏览 4 评论 0原文

我有一个适用于 Windows Mobile 6.x 的 Visual Studio 2008 C++ 应用程序,我在其中计算给定进程可用的可用虚拟内存量。 (我意识到它没有考虑碎片。)我的代码基本上如下所示:

MEMORY_BASIC_INFORMATION mbi = { 0 };

/// total free memory available to the process
DWORD free = 0;

/// base memory address for the given process index (2-33). 
DWORD slot_base_addr = process_index * 0x02000000;

/// look at each memory region for the process. 
for( DWORD offset = 0x10000; 
     offset < 0x02000000; 
     offset += mbi.RegionSize )
{
    ::VirtualQuery( ( void* )( slot_base_addr + offset ), 
                    &mbi, 
                    sizeof( MEMORY_BASIC_INFORMATION ) );

    if( mbi.State == MEM_FREE )
    {
        free += ( mbi.RegionSize - ( ( ~( DWORD )mbi.BaseAddress + 1 ) & 0xffff ) ) & 0xffff0000;
    }
}
NKDbgPrintfW( L"%d bytes free\r\n", free );

我可以通过其他 API 确认这似乎工作正常。我的问题是这一行在做什么:

free += ( mbi.RegionSize - ( ( ~( DWORD )mbi.BaseAddress + 1 ) & 0xffff ) ) & 0xffff0000;

为什么这不仅仅是:

free += mbi.RegionSize;

我在 Usenet 由 MSFT 员工 Ross Jordan 发布。

谢谢, PaulH


编辑:

例如。对于进程槽 2,这是每个空闲内存块的列表,其中空闲内存量由 Ross Jordan (RS) 算法和 RegionSize (RS) 给出。

Slot: 2. Range: 0x04000000 - 0x06000000
    RS:    16,384 bytes RJ:         0 bytes diff: 16384
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:    36,864 bytes RJ:         0 bytes diff: 36864
    RS:    65,536 bytes RJ:    65,536 bytes diff: 0
    RS:    53,248 bytes RJ:         0 bytes diff: 53248
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS: 7,671,808 bytes RJ: 7,667,712 bytes diff: 4096
    RS: 1,921,024 bytes RJ: 1,900,544 bytes diff: 20480
    RS: 7,491,584 bytes RJ: 7,471,104 bytes diff: 20480
    RS: 3,252,224 bytes RJ: 3,211,264 bytes diff: 40960
    RS:   262,144 bytes RJ:   262,144 bytes diff: 0

RS: Total VM Free: 20,811,776 bytes.
RJ: Total VM Free: 20,578,304 bytes.

编辑2:

汉斯引导我找到了答案。这只是一种奇特的方法,但假设分配大小为 64KB。

SYSTEM_INFO si = { 0 };
::GetSystemInfo( &si );

free += mbi.RegionSize - mbi.RegionSize % si.dwAllocationGranularity;

I have a Visual Studio 2008 C++ application for Windows Mobile 6.x where I'm counting the amount of free virtual memory available for a given process. (I realize it is not taking fragmentation in to account.) My code looks basically like this:

MEMORY_BASIC_INFORMATION mbi = { 0 };

/// total free memory available to the process
DWORD free = 0;

/// base memory address for the given process index (2-33). 
DWORD slot_base_addr = process_index * 0x02000000;

/// look at each memory region for the process. 
for( DWORD offset = 0x10000; 
     offset < 0x02000000; 
     offset += mbi.RegionSize )
{
    ::VirtualQuery( ( void* )( slot_base_addr + offset ), 
                    &mbi, 
                    sizeof( MEMORY_BASIC_INFORMATION ) );

    if( mbi.State == MEM_FREE )
    {
        free += ( mbi.RegionSize - ( ( ~( DWORD )mbi.BaseAddress + 1 ) & 0xffff ) ) & 0xffff0000;
    }
}
NKDbgPrintfW( L"%d bytes free\r\n", free );

I can confirm with other APIs that this seems to work perfectly. My question is what this line is doing:

free += ( mbi.RegionSize - ( ( ~( DWORD )mbi.BaseAddress + 1 ) & 0xffff ) ) & 0xffff0000;

Why is this not just:

free += mbi.RegionSize;

I found the former line on a Usenet post by MSFT employee Ross Jordan.

Thanks,
PaulH


Edit:

For example. For process slot 2, this is a list of each free memory block with the amount of free memory given by both the Ross Jordan (RS) algorithm and just the RegionSize (RS).

Slot: 2. Range: 0x04000000 - 0x06000000
    RS:    16,384 bytes RJ:         0 bytes diff: 16384
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:    36,864 bytes RJ:         0 bytes diff: 36864
    RS:    65,536 bytes RJ:    65,536 bytes diff: 0
    RS:    53,248 bytes RJ:         0 bytes diff: 53248
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS:     4,096 bytes RJ:         0 bytes diff: 4096
    RS: 7,671,808 bytes RJ: 7,667,712 bytes diff: 4096
    RS: 1,921,024 bytes RJ: 1,900,544 bytes diff: 20480
    RS: 7,491,584 bytes RJ: 7,471,104 bytes diff: 20480
    RS: 3,252,224 bytes RJ: 3,211,264 bytes diff: 40960
    RS:   262,144 bytes RJ:   262,144 bytes diff: 0

RS: Total VM Free: 20,811,776 bytes.
RJ: Total VM Free: 20,578,304 bytes.

Edit 2:

Hans led me to the answer. It's just a fancy way of doing this, but assuming that the allocation size is 64KB.

SYSTEM_INFO si = { 0 };
::GetSystemInfo( &si );

free += mbi.RegionSize - mbi.RegionSize % si.dwAllocationGranularity;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

十六岁半 2024-10-07 02:48:55

VirtualAlloc 的分配粒度通常为 64KB。如果 AllocationBase 不是 64KB 的倍数,他会尝试做一些有意义的事情。我认为这根本没有意义,他的位掩码仍然假设粒度为 64KB,并且他不使用 SYSTEM_INFO.dwAllocationGranularity。其中有这样的评论:

该值被硬编码为 64 KB
过去,但其他硬件
架构可能需要不同的
值。

在极少数情况下(不是 64KB),此代码将生成垃圾值。只需按 RegionSize 进行操作即可。

Allocation granularity for VirtualAlloc is normally 64KB. He tries to do something meaningful if the AllocationBase is not a multiple of 64KB. I don't think it is meaningful at all, his bitmasks still assume a granularity of 64KB and he doesn't use SYSTEM_INFO.dwAllocationGranularity. Which has this comment:

This value was hard coded as 64 KB in
the past, but other hardware
architectures may require different
values.

In the very rare case where it is not 64KB, this code would generate junk values. Just zap it, go by RegionSize.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文