• windows 堆管理


    windows堆管理是建立在虚拟内存管理的基础之上的,每个进程都有独立的4GB的虚拟地址空间,其中有2GB的属于用户区,保存的是用户程序的数据和代码,而系统在装载程序时会将这部分内存划分为4个段从低地址到高地址依次为静态存储区,代码段,堆段和栈段,其中堆的生长方向是从低地址到高地址,而栈的生长方向是从高地址到低地址。
    程序申请堆内存时,系统会在虚拟内存的基础上分配一段内存,然后记录下来这块的大小和首地址,并且在对应内存块的首尾位置各有相应的数据结构,所以在堆内存上如果发生缓冲区溢出的话,会造成程序崩溃,这部分没有硬件支持,所有管理算法都有开发者自己设计实现。
    堆内存管理的函数主要有HeapCreate、HeapAlloc、HeapFree、HeapRealloc、HeapDestroy、HeapWalk、HeapLock、HeapUnLock。下面主要通过一些具体的操作来说明这些函数的用法。

    堆内存的分配与释放

    堆内存的分配主要用到函数HeapAlloc,下面是这个函数的原型:

    LPVOID HeapAlloc(
      HANDLE hHeap, //堆句柄,表示在哪个堆上分配内存
      DWORD dwFlags, //分配的内存的相关标志
      DWORD dwBytes //大小
    );

    堆句柄可以使用进程默认堆也可以使用用户自定义的堆,自定义堆使用函数HeapCreate,函数返回堆的句柄,使用GetProcessHeap可以获取系统默认堆,返回的也是一个堆句柄。分配内存的相关标志有这样几个值:
    HEAP_NO_SERIALIZE:这个表示对堆内存不进行线程并发控制,由于系统默认会进行堆的并发控制,防止多个线程同时分配到了同一个堆内存,如果程序是单线程程序则可以添加这个选项,适当提高程序运行效率。
    HEAP_ZERO_MEMORY:这个标志表示在分配内存的时候同时将这块内存清零。
    HeapCreate函数的原型如下:

    HANDLE HeapCreate(
      DWORD flOptions, //堆的相关属性
      DWORD dwInitialSize, //堆初始大小
      DWORD dwMaximumSize //堆所占内存的最大值
    );

    flOptions的取值如下:
    HEAP_NO_SERIALIZE:取消并发控制
    HEAP_SHARED_READONLY:其他进程可以以只读属性访问这个堆
    dwInitialSize, dwMaximumSize这两个值如果都是0,那么堆内存的初始大小由系统分配,并且堆没有上限,会根据具体的需求而增长。下面是使用的例子:

        //在系统默认堆中分配内存
        srand((unsigned int)time(NULL));
        HANDLE hHeap = GetProcessHeap();
        int nCount = 1000;
        float *pfArray = (float *)HeapAlloc(hHeap, HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, nCount * sizeof(float));
        for (int i = 0; i < nCount; i++)
        {
            pfArray[i] = 1.0f * rand();
        }
    
        HeapFree(hHeap, HEAP_NO_SERIALIZE, pfArray);
    
        //在自定义堆中分配内存
        hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 0, 0);
        pfArray = (float *)HeapAlloc(hHeap, HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, nCount * sizeof(float));
        for (int i = 0; i < nCount; i++)
        {
            pfArray[i] = 1.0f * rand();
        }
    
        HeapFree(hHeap, HEAP_NO_SERIALIZE, pfArray);
        HeapDestroy(hHeap);

    遍历进程中所有堆的信息:

    便利堆的信息主要用到函数HeapWalk,该函数的原型如下:

    BOOL WINAPI HeapWalk(
      __in          HANDLE hHeap,//堆的句柄
      __in_out      LPPROCESS_HEAP_ENTRY lpEntry//返回堆内存的相关信息
    );

    下面是PROCESS_HEAP_ENTRY的原型:

    typedef struct _PROCESS_HEAP_ENTRY {
        PVOID lpData;
        DWORD cbData;
        BYTE cbOverhead;
        BYTE iRegionIndex;
        WORD wFlags;
        union {
            struct {
                HANDLE hMem;
                DWORD dwReserved[3];
                } Block;
            struct {
                DWORD dwCommittedSize;
                DWORD dwUnCommittedSize;
                LPVOID lpFirstBlock;
                LPVOID lpLastBlock;
                } Region;
            };
    } PROCESS_HEAP_ENTRY,  *LPPROCESS_HEAP_ENTRY;

    这个结构中的公用体具体使用哪个与wFlags相关,下面是这些值得具体含义:

    wFlags 堆入口含义 lpData cbData cbOverhead块前堆数据结构大小 iRegionIndex Block Region
    PROCESS_HEAP_ENTRY_BUSY 被分配的内存块 首地址 内存块大小 内存块前堆数据结构 所在区域索引 无意义 无意义
    PROCESS_HEAP_ENTRY_DDESHARE DDE共享内存块 首地址 内存块大小 内存块前堆数据结构 所在区域索引 无意义 无意义
    PROCESS_HEAP_ENTRY_MOVEABLE 可移动的内存块(兼容GlobalAllocLocalAlloc) 首地址(可移动内存句柄的首地址) 内存块大小 内存块前堆数据结构 所在区域索引 与PROCESS_HEAP_ENTRY_BUSY标志一同指定可移动内存句柄值 无意义
    PROCESS_HEAP_REGION 已提交的堆虚拟内存区域 区域开始地址 区域大小 区域前堆数据结构 区域索引 无意义 虚拟内存区域详细信息
    PROCESS_HEAP_UNCOMMITTED_RANGE 未提交的堆虚拟内存区域 区域开始地址 区域大小 区域前堆数据结构 区域索引 无意义 无意义

    下面是时遍历堆内存的例子:

        PHANDLE pHeaps = NULL;
        //当传入的参数为0和NULL时,函数返回进程中堆的个数
        int nCount = GetProcessHeaps(0, NULL);
        pHeaps = new HANDLE[nCount];
        //获取进程所有堆句柄
        GetProcessHeaps(nCount, pHeaps);
        PROCESS_HEAP_ENTRY phe = {0};
        for (int i = 0; i < nCount; i++)
        {
            cout << "Heap handle: 0x" << pHeaps[i] << '
    ';
            //在读取堆中的相关信息时需要将堆内存锁定,防止程序向堆中写入数据
            HeapLock(pHeaps[i]);
            HeapWalk(pHeaps[i], &phe);
            //输出堆信息
            cout << "	Size: " << phe.cbData << " - Overhead: "  
                << static_cast<DWORD>(phe.cbOverhead) << '
    ';     
            cout << "	Block is a";         
            if(phe.wFlags & PROCESS_HEAP_REGION)  
            {       
                cout << " VMem region:
    ";   
                cout << "	Committed size: " << phe.Region.dwCommittedSize << '
    ';     
                cout << "	Uncomitted size: " << phe.Region.dwUnCommittedSize << '
    ';    
                cout << "	First block: 0x" << phe.Region.lpFirstBlock << '
    ';      
                cout << "	Last block: 0x" << phe.Region.lpLastBlock << '
    ';    
            }           
            else     
            {      
                if(phe.wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE)
                {             
                    cout << "n uncommitted range
    "; 
                }          
                else if(phe.wFlags & PROCESS_HEAP_ENTRY_BUSY)   
                {      
                    cout << "n Allocated range: Region index - "   
                        << static_cast<unsigned>(phe.iRegionIndex) << '
    ';          
                    if(phe.wFlags & PROCESS_HEAP_ENTRY_MOVEABLE)  
                    {                
                        cout << "	Movable: Handle is 0x" << phe.Block.hMem << '
    ';  
                    }               
                    else if(phe.wFlags & PROCESS_HEAP_ENTRY_DDESHARE)       
                    {                  
                        cout << "	DDE Sharable
    ";    
                    }             
                }       
                else cout << " block, no other flags specified
    ";        
            }          
            cout << std::endl;       
            HeapUnlock(pHeaps[i]);
            ZeroMemory(&phe, sizeof(PROCESS_HEAP_ENTRY));
        }
        delete[] pHeaps;

    另外堆还有其他操作,比如使用HeapSize获取分配的内存大小,使用HeapValidate可以校验一个对内存的完整性,从而提早发现”野指针”等等。

  • 相关阅读:
    jquery取iframe中元素
    jquery 复选框全选/全不选切换 普通DOM元素点击选中/取消选中切换
    css横向 弹性盒子布局的一些属性
    css3 html5画心
    herf 和 src 的区别
    AngularJS bind
    I18n国际化
    jqgrid获取数据条数
    @ModelAttribute设置request、response、session对象
    js浏览器判断函数
  • 原文地址:https://www.cnblogs.com/lanuage/p/7725741.html
Copyright © 2020-2023  润新知