Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 单个VirtualAlloc分配使用的内存(和其他资源)_C++_C_Winapi_Memory Management - Fatal编程技术网

C++ 单个VirtualAlloc分配使用的内存(和其他资源)

C++ 单个VirtualAlloc分配使用的内存(和其他资源),c++,c,winapi,memory-management,C++,C,Winapi,Memory Management,每个VirtualAlloc(xxxx,yyy,MEM_RESERVE,zzz)使用了多少内存或其他资源 当我分配一个大数据块时,资源消耗(例如内核分页/非分页池)是否有任何差异,如下所示: VirtualAlloc( xxxx, 1024*1024, MEM_RESERVE, PAGE_READWRITE ) VirtualAlloc( xxxx, 64*1024, MEM_RESERVE, PAGE_READWRITE ); VirtualAlloc( xxxx+1*64*1024, 64

每个
VirtualAlloc(xxxx,yyy,MEM_RESERVE,zzz)
使用了多少内存或其他资源

当我分配一个大数据块时,资源消耗(例如内核分页/非分页池)是否有任何差异,如下所示:

VirtualAlloc( xxxx, 1024*1024, MEM_RESERVE, PAGE_READWRITE )
VirtualAlloc( xxxx, 64*1024, MEM_RESERVE, PAGE_READWRITE );
VirtualAlloc( xxxx+1*64*1024, 64*1024, MEM_RESERVE, PAGE_READWRITE );
VirtualAlloc( xxxx+2*64*1024, 64*1024, MEM_RESERVE, PAGE_READWRITE );
...
VirtualAlloc( xxxx+15*64*1024, 64*1024, MEM_RESERVE, PAGE_READWRITE );
或多个较小的块,如下所示:

VirtualAlloc( xxxx, 1024*1024, MEM_RESERVE, PAGE_READWRITE )
VirtualAlloc( xxxx, 64*1024, MEM_RESERVE, PAGE_READWRITE );
VirtualAlloc( xxxx+1*64*1024, 64*1024, MEM_RESERVE, PAGE_READWRITE );
VirtualAlloc( xxxx+2*64*1024, 64*1024, MEM_RESERVE, PAGE_READWRITE );
...
VirtualAlloc( xxxx+15*64*1024, 64*1024, MEM_RESERVE, PAGE_READWRITE );
如果有人不知道答案,但可以建议一个实验,可以检查它,这将是有益的


其动机是我想在Windows下实现将内存返回操作系统。我的想法是通过执行一系列小型(分配粒度)调用来替换单个大型VirtualAlloc调用,这样我就可以对每个调用调用VirtualFree。我知道这样分配大数据块会比较慢,但是会有任何资源消耗损失吗?

根据我对页面表的理解,您有1024页的数据块,每页一个字。无论如何,成本是页数,而不是分配。无论如何,可能还有其他机制会在每次分配时“额外”花费(我只是不知道)

不过:使用VirtualFree,您可以有选择地取消单个页面或页面范围的提交。对于取消提交的页面,虚拟地址范围(在您的进程内)仍然保留,但没有为其分配任何物理内存(RAM或交换文件)。以后可以使用VirtualAlloc再次提交这些页面

因此,除非您需要为进程中的其他分配器释放地址空间,否则您可以使用此机制有选择地向操作系统请求和返回内存

[编辑]

测量
为了测量,我想比较两种算法在一个或多个典型负载下的性能(人工/随机分配模式、分配繁重的“真实世界”应用程序等)。优点:你得到了“整个故事”-内核资源、页面碎片、应用程序性能等。缺点:你必须实现这两种算法,你不知道原因,而且你可能需要非常特殊的情况才能从噪音中发现可测量的差异

地址空间碎片警告-小心返回算法。当以“谁有空”的方式将各个页面返回到进程时,您可能会得到一个碎片化的地址空间,该地址空间有80%的可用内存,但没有连续的100K可用内存。

您可以尝试使用“perfmon”并添加计数器(例如内存),以开始了解VirtualAlloc正在使用哪些资源。您必须在调用VirtualAlloc之前和之后拍摄快照


另一个选项是调试WinDBG下调用VirtualAlloc的进程,并使用与内存相关的命令了解实际发生的情况。

仅供参考,您可以使用GetProcessMemoryInfo和GlobalMemoryStatusEx获取一些内存使用量测量值

void DisplayMemoryUsageInformation()
{
    HANDLE hProcess = GetCurrentProcess();
    PROCESS_MEMORY_COUNTERS pmc;
    ZeroMemory(&pmc,sizeof(pmc));
    GetProcessMemoryInfo(hProcess,&pmc, sizeof(pmc));
    std::cout << "PageFaultCount:             " << pmc.PageFaultCount             << std::endl;
    std::cout << "PeakWorkingSetSize:         " << pmc.PeakWorkingSetSize         << std::endl;
    std::cout << "WorkingSetSize:             " << pmc.WorkingSetSize             << std::endl;
    std::cout << "QuotaPeakPagedPoolUsage:    " << pmc.QuotaPeakPagedPoolUsage    << std::endl;
    std::cout << "QuotaPagedPoolUsage:        " << pmc.QuotaPagedPoolUsage        << std::endl;
    std::cout << "QuotaPeakNonPagedPoolUsage: " << pmc.QuotaPeakNonPagedPoolUsage << std::endl;
    std::cout << "QuotaNonPagedPoolUsage:     " << pmc.QuotaNonPagedPoolUsage     << std::endl;
    std::cout << "PagefileUsage:              " << pmc.PagefileUsage              << std::endl;
    std::cout << "PeakPagefileUsage:          " << pmc.PeakPagefileUsage          << std::endl;

    MEMORYSTATUSEX msx;
    ZeroMemory(&msx,sizeof(msx));
    msx.dwLength = sizeof(msx);
    GlobalMemoryStatusEx(&msx);
    std::cout << "MemoryLoad:                 " << msx.dwMemoryLoad               << std::endl;
    std::cout << "TotalPhys:                  " << msx.ullTotalPhys               << std::endl;
    std::cout << "AvailPhys:                  " << msx.ullAvailPhys               << std::endl;
    std::cout << "TotalPageFile:              " << msx.ullTotalPageFile           << std::endl;
    std::cout << "AvailPageFile:              " << msx.ullAvailPageFile           << std::endl;
    std::cout << "TotalVirtual:               " << msx.ullTotalVirtual            << std::endl;
    std::cout << "AvailVirtual:               " << msx.ullAvailVirtual            << std::endl;
    std::cout << "AvailExtendedVirtual:       " << msx.ullAvailExtendedVirtual    << std::endl;
}
void DisplayMemoryUsageInformation()
{
HANDLE hProcess=GetCurrentProcess();
进程\内存\计数器pmc;
零内存(&pmc,sizeof(pmc));
GetProcessMemoryInfo(hProcess,&pmc,sizeof(pmc));

std::coutZero,或实际上为零,通过使用reserve参数进行VirtualAlloc调用来使用内存。这只会在进程中保留地址空间。只有通过使用带有commit参数的VirtualAlloc实际返回带有页面的地址,才会使用内存。 这本质上就是虚拟字节(占用的地址空间量)和私有字节(提交的内存量)之间的区别。 您对VirtualAlloc()的两种使用都将保留相同的内存量,因此它们在资源消耗方面是等效的。 我建议您在决定编写自己的分配器之前先对此进行一些阅读。马克·鲁西尼维奇(Mark Russinivich)是最好的资料来源之一。您应该检查一下。他写了一些名为“推动限制”的条目,涵盖了其中的一些内容。如果您想了解真正的细节,那么您应该阅读他的书().这是迄今为止我读过的关于windows如何管理内存(以及其他所有内容)的最佳参考资料

(编辑)其他信息: 相关的部分是“页面目录”和“页面表”。根据我以前在x86上的Microsoft Windows Internal…副本,每个进程有一个页面目录,有1024个条目。最多有512个页面表。进程中使用的每个32位指针分为3个部分[31-22]页面目录索引[21-12]是页表索引,[11-0]是页中的字节索引。 将virtual alloc与reserve参数一起使用时,将创建页面目录项(32位),并创建页面表项(32位)。此时,不会为保留内存创建页面。 查看此信息的最佳方法是使用内核调试器。我建议使用LiveKD(sysinternals)。您可以在不连接远程计算机的情况下使用LiveKD,但它不允许实时调试。加载LiveKD并选择您的进程。然后您可以运行!PTE命令检查进程的页表


同样,我建议阅读Windows内部的内容。在我的版本(第四版)中有一章(超过100页)这包括了所有这些,并提供了在liveKD中遍历各种数据结构的示例。

谢谢,但我关心的是释放地址空间。因此,取消提交对我来说是不够的。好吧……你可以设置一个测试。让我们知道它会带来什么。但是测量什么以及如何测量?我如何测量内核intern的消耗al resources?由于我对目前唯一的答案不满意,现在有了悬赏。我期望从答案中得到的是:-详细描述,使用VirtualAlloc(…MEM_RESERVE…)调用的单个块使用的内核资源-或者详细实验如何告诉我