前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Windows 堆内存管理

Windows 堆内存管理

作者头像
我与梦想有个约会
发布2023-10-21 14:19:28
2010
发布2023-10-21 14:19:28
举报
文章被收录于专栏:jiajia_deng

Windows 堆内存是性能仅次于虚拟内存的内存管理机制。它不像虚拟内存,每次分配至少是一个页面(4K),它可以灵活的只分配 1 个字节来使用,不浪费内存的空间。但你分配的内存必须由自己维护释放。下面演示了堆内存的使用方法。

最简单的堆使用

代码语言:javascript
复制
#include <Windows.h>
#include <stdio.h>

int main()
{
    // 使用系统给每个进程提供的默认堆
    HANDLE hHeap = GetProcessHeap();
    float* fArray = (float*)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 1000 * sizeof(float));
    for (int i = 0; i < 1000; i++)
    {
        fArray[i] = 1.0f * rand();
    }
    HeapFree(hHeap, 0, fArray);

    // 创建一个私有堆
    hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 0, 0);
    fArray = (float*)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 1000 * sizeof(float));
    for (int i = 0; i < 1000; i++)
    {
        fArray[i] = 1.0f * rand();
    }

    // 类似 C 语言库函数的 realloc 函数
    fArray = (float*)HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, fArray, 2 * 1000 * sizeof(float));
    for (int i = 0; i < 2 * 1000; i++)
    {
        fArray[i] = 1.0f * rand();
    }

    HeapFree(hHeap, 0, fArray);
    // 销毁堆
    HeapDestroy(hHeap);
    return 0;
}

查询进程中堆内存的详细使用信息

同虚拟内存一样,堆内存也可以遍历得到每一块堆内存的使用情况,主要用到的就是 HeapWalk 函数,下面的图片介绍了不同堆类型的不同属性值,图片下面是代码实现,参考者图看代码更容易理解。

2016-04-10_185012
2016-04-10_185012
代码语言:javascript
复制
#include <tchar.h>
#include <windows.h>
#include <time.h>
#include <iostream>
#include <vector>

void DisplayHeapsInfo(std::ostream& out = std::cout);

int _tmain()
{
    DisplayHeapsInfo();
    _tsystem(_T("pause"));
    return 0;
}

void DisplayHeapsInfo(std::ostream& out /*= std::cout*/)
{
    // 得到有多少个堆内存块
    // 初始化,设定最大元素为 GetProcessHeaps 返回的值,防止数组动态增长分配不必要的内存
    std::vector<HANDLE> heaps(GetProcessHeaps(0, NULL));
    // 得到首个堆的地址
    GetProcessHeaps(heaps.size(), &heaps[0]);

    DWORD totalBytes = 0;
    for (DWORD i = 0; i < heaps.size(); i++)
    {
        // 依次遍历
        out << "Heap handle: 0x" << heaps[i] << '\n';
        PROCESS_HEAP_ENTRY phi = { 0 };
        while (HeapWalk(heaps[i], &phi))
        {
            out << "Block Start Address: 0x" << phi.lpData << '\n';
            out << "\tSize: " << phi.cbData << " - Overhead: " 
                << static_cast<DWORD>(phi.cbOverhead);
            out << "\tBlock is a";

            // 已提交的堆虚拟内存区域
            if (phi.wFlags & PROCESS_HEAP_REGION)
            {
                out << " VMem region:\n";
                out << "\tCommitted size: " << phi.Region.dwCommittedSize << '\n';
                out << "\tUnCommitted size: " << phi.Region.dwUnCommittedSize << '\n';
                out << "\tFirst block: 0x" << phi.Region.lpFirstBlock << '\n';
                out << "\tLast block: 0x" << phi.Region.lpLastBlock << '\n';
            }
            else
            {
                // 未提交的堆虚拟内存区域
                if (phi.wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE)
                {
                    out << "n uncommitted range\n";
                }
                // 已经被分配的堆内存区域
                else if (phi.wFlags & PROCESS_HEAP_ENTRY_BUSY)
                {
                    totalBytes += phi.cbData;
                    out << "n Allocated range: Region index - "
                        << static_cast<unsigned>(phi.iRegionIndex) << '\n';
                    if (phi.wFlags & PROCESS_HEAP_ENTRY_MOVEABLE)
                    {
                        out << "\tMoable: Handle is 0x" << phi.Block.hMem << '\n';
                    }
                    else if (phi.wFlags & PROCESS_HEAP_ENTRY_DDESHARE)
                    {
                        out << "\tDDE Sharable\n";
                    }
                }
                else
                {
                    out << " block, no other flags specified\n";
                }
            }
            out << std::endl;
        }
    }
    out << "End of report - total of " << std::dec << totalBytes << " allocated" << std::endl;
}

低碎块堆

所谓低碎块堆实际就是增加了内存对齐的机制,对齐后内存最小颗粒度为 8 个字节,分配内存时,比如指定了 10 个字节,那么实际也会分配 16 (8的最小整数倍)个字节。这样做目的是为了减少内存碎块化严重而导致缺少很多连续的内存地址空间。降低了因需要合并内存碎块而造成的额外开销,从而提升了性能。以下是具体实现代码。

代码语言:javascript
复制
#include <tchar.h>
#include <windows.h>

int _tmain()
{
    HANDLE  hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 0, 0);
    ULONG   HeapFragValue = 2;
    if (HeapSetInformation(hHeap,
        HeapCompatibilityInformation,
        &HeapFragValue,
        sizeof(HeapFragValue)))
    {
        // LFH Open,低碎块堆已经打开,其他按普通堆正常使用即可。
    }
    HeapDestroy(hHeap);
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016-04-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 最简单的堆使用
  • 查询进程中堆内存的详细使用信息
  • 低碎块堆
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档