堆(Heap)和栈(Stack)不同,堆是给进程用的,用来存储各个线程申请的内存块。
不能同时在堆上进行Alloc操作,这就意味这如果2个线程同时执行new操作,那么一个可以执行,另一个要等到这个执行完毕才可以执行new——否则的话,可能返回同一个地址,而线程还傻乎乎的以为是不同的呢。因此,如果想获取高效率而不出现问题(当然还有其他原因),那么可以另外创建一个堆来使用。使用函数 HeapCreate来创建一个堆。
    从堆中分配内存:HeapAlloc
    改变已分配内存大小:HeapReAlloc
    获取已分配内存块大小:HeapSize
    释放已分配内存块:HeapFree
    销毁堆:HeapDestroy
可是,此时使用new操作符,仍将在默认的堆上分配空间,我们需要在新的堆上来分配空间,此时需要重载对应类的new和delete操作符。
class CSomeClass
{
private :
   
static HANDLE s_hHeap;
   
static UINT s_uNumAllocsInHeap;
   
// Other private data and member functions
public :
   
void * operator new (size_t size);
   
void operator delete ( void * p);
   
// Other public data and member functions
};

HANDLE CSomeClass::s_hHeap
= NULL;
UINT CSomeClass::s_uNumAllocsInHeap
= 0 ;

void * CSomeClass:: operator new (size_t size)
{
   
if (s_hHeap == NULL)
    {
      
// Heap does not exist; create it.
       s_hHeap = HeapCreate(HEAP_NO_SERIALIZE, 0 , 0 );

      
if (s_hHeap == NULL)
         
return (NULL);
    }
   
// The heap exists for CSomeClass objects.
    void * p = HeapAlloc(s_hHeap, 0 , size);

   
if (p != NULL)
    {
      
// Memory was allocated successfully; increment
      
// the count of CSomeClass objects in the heap.
       s_uNumAllocsInHeap ++ ;
    }

   
// Return the address of the allocated CSomeClass object.
    return (p);
}
void CSomeClass:: operator delete ( void * p)
{
   
if (HeapFree(s_hHeap, 0 , p))
    {
      
// Object was deleted successfully.
       s_uNumAllocsInHeap -- ;
    }

   
if (s_uNumAllocsInHeap == 0 )
    {
      
// If there are no more objects in the heap,
      
// destroy the heap.
       if (HeapDestroy(s_hHeap))
       {
         
// Set the heap handle to NULL so that the new operator
         
// will know to create a new heap if a new CSomeClass
         
// object is created.
          s_hHeap = NULL;
       }
    }
}

1.堆

                一个进程中可以有多个堆

2..Common API:

HeapCreate            

HeapSize

HeapReAlloc

HeapFree               

HeapDestroy          

GetProcessHeaps

HeapValidate         

HeapCompact

HeapLock               

HeapUnlock

HeapWalk

 

HANDLE HeapCreate(
DWORD
flOptions,       // heap allocation attributes
SIZE_T dwInitialSize, // initial heap size
SIZE_T dwMaximumSize   // maximum heap size
);

对于flOptions 参数,如果有多线程占有对堆的访问和使用的时候,避免使用HEAP_NO_SERIALIZE参数。

对于 dwMaximumSize参数,如果非0,则即为最大值,如果为0,则表名这个堆是可扩展的。

 

LPVOID HeapAlloc(
HANDLE
hHeap,   // handle to private heap block
DWORD dwFlags, // heap allocation control
SIZE_T dwBytes // number of bytes to allocate );

dwFlags,可以指定HEAP_GENERATE_EXCEPTIONS参数,这样当堆分配出现问题的时候可以抛出异常给程序捕获。

 

LPVOID HeapReAlloc(
HANDLE
hHeap,   // handle to heap block
DWORD dwFlags, // heap reallocation options LPVOID lpMem,   // pointer to memory to reallocate
SIZE_T dwBytes // number of bytes to reallocate
);

dwFlags:HEAP_REALLOC_IN_PLACE_ONLY指明不许移动堆中的内存块。

 

DWORD HeapSize(
HANDLE
hHeap, // handle to heap
DWORD dwFlags, // heap size options
LPCVOID lpMem // pointer to memory
);

获取内存块的大小

 

当不再使用堆中的内存时,可以释放内存:

BOOL HeapFree(
HANDLE
hHeap, // handle to heap
DWORD dwFlags, // heap free options
LPVOID lpMem // pointer to memory );

 

当不再需要堆的时候,可以销毁堆:

BOOL HeapDestroy(
HANDLE
hHeap   // handle to heap
);

 

HANDLE GetProcessHeap(VOID);
返回调用此函数的的进程的堆
DWORD GetProcessHeaps(
  DWORD NumberOfHeaps,  // maximum number of heap handles 
  PHANDLE ProcessHeaps  // buffer for heap handles
);
得到进程中所有的堆的handle
Remarks

The GetProcessHeap function allows you to allocate memory from the process heap without having to first create a heap with the HeapCreate function, as shown in this example:

HeapAlloc(GetProcessHeap(), 0, dwBytes);

Note   The handle obtained by calling this function should not be used in calls to the HeapDestroy function.

To guard against an access violation, use structured exception handling to protect any code that writes to or reads from a heap. For more information on structured exception handling with memory accesses,

see Reading and Writing and Structured Exception Handling.

GetProcessHeaps返回当前进程的进程堆(process heap)的handle加上由HeapCreate创建的所有私有的heap的handle。

GetProcessHeap仅返回当前进程的进程堆(process heap)。

规则很简单:

1. 永远不要用GetProcessHeaps。尤其是不推荐使用GetProcessHeaps获取私有堆的handle,因为这将导致无法预估的后果。

2. 使用GetProcessHeap去获取当前进程的进程堆(process heap)。

3. 那些由HeapCreate创建出来的私有堆,必须由创建者自己去维护其生命周期。也就是说,只有创建者才可以去使用这些private heap的handle。

讨论

为什么不推荐使用GetProcessHeaps获取私有堆的handle?为什么这将导致无法预估的后果?

 

那传递给headalloc用GetProcessHeap还是用heapCreate好?

 

如果可能很大当然是CreateHeap要好,因为它可以动态Destroy,而程序堆只要程序在运行,你就没办法Destroy,结果就像我们看到Windows的控件一样,一个打开文件的对话框,明明关闭了,可你的程序内存占用还是没减,因为程序堆的内存是不需要释放也无法释放,它在程序结束后自动Destroy,而自己创建的则Destroy后,你程序的内存占用就少了。也就是能成功Destroy.

 

代码片段:

if (HIWORD(cbtcwW->lpcs->lpszName)) {
            len = WideCharToMultiByte( CP_ACP, 0, cbtcwW->lpcs->lpszName, -1, NULL, 0, NULL, NULL );
            csA.lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(CHAR) );
            WideCharToMultiByte( CP_ACP, 0, cbtcwW->lpcs->lpszName, -1, (LPSTR)csA.lpszName, len, NULL, NULL );
        }

        if (HIWORD(cbtcwW->lpcs->lpszClass)) {
            len = WideCharToMultiByte( CP_ACP, 0, cbtcwW->lpcs->lpszClass, -1, NULL, 0, NULL, NULL );
            csA.lpszClass = HeapAlloc( GetProcessHeap(), 0, len*sizeof(CHAR) );
            WideCharToMultiByte( CP_ACP, 0, cbtcwW->lpcs->lpszClass, -1, (LPSTR)csA.lpszClass, len, NULL, NULL );
        }

        ret = proc( code, wparam, (LPARAM)&cbtcwA );
        cbtcwW->hwndInsertAfter = cbtcwA.hwndInsertAfter;
        if (HIWORD(csA.lpszName)) HeapFree( GetProcessHeap(), 0, (LPSTR)csA.lpszName );
        if (HIWORD(csA.lpszClass)) HeapFree( GetProcessHeap(), 0, (LPSTR)csA.lpszClass );
    }

 

lpNewperHandleContext = (PPER_HANDLE_ CONTEXT)HeapAlloc(

                            GetProcessHeap(),
                            HEAP_ZERO_MEMORY,
                            sizeof(PER_HANDLE_CONTEXT)

                            );

BOOL HeapWalk(
HANDLE
hHeap,                 // heap to enumerate
LPPROCESS_HEAP_ENTRY lpEntry // state information
);

枚举系统中的堆,主要是用来调试的

在循环调用HeapWalk的时候,必须使用HeapLock和HeapUnlock函数,这样,当遍历堆栈时,其他线程将无法分配和释放堆栈中的内存块。

 

 

使用heapwalk的代码示例:

// heap.h
#include <tlhelp32.h>

DWORD* SearchHeaps(DWORD* data, DWORD dataSize);

DWORD* SearchHeapNT(HANDLE heap, DWORD* data, DWORD dataSize);
DWORD* SearchHeap9x(HEAPLIST32* heapInfo, DWORD* data, DWORD dataSize);

#include <windows.h>
#include <tlhelp32.h>
#include "log.h"
#include "heap.h"

/* Searches specified all process heaps for certain data */
DWORD* SearchHeaps(DWORD* data, DWORD dataSize)
{
// Due to Win32 API inconsistencies, we need to use different API:
// depending on the version of the operating system, we're running on
//     HeapWalk on WinNT/2000/XP,
//     Heap32First/Heap32Last on Win95/98/Me
OSVERSIONINFO osInfo;
osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osInfo);

TRACE2("OS Major version: %d", osInfo.dwMajorVersion);
TRACE2("OS Minor version: %d", osInfo.dwMinorVersion);
TRACE2("OS Platform Id: %d", osInfo.dwPlatformId);

TRACE2("Default process heap: %08x", (DWORD)GetProcessHeap());

if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
   // get handles for heaps (up to 1000)
   HANDLE heaps[1000];
   int numHeaps = GetProcessHeaps(1000, heaps);
   TRACE2("Process uses %d heaps.", numHeaps);

   for (int i=0; i<numHeaps; i++)
   {
    TRACE2("Searching heap #%d...", i);
    HANDLE heap = heaps[i];
    DWORD* p = SearchHeapNT(heap, data, dataSize);
    if (p != NULL) return p;
   }
   // didn't find the data
   return NULL;
}
else
{
   // NOTE about Win95/98/Me:
   //
   // Ideally, a straight-forward and simple approach would be used
   // to search the application's heaps using Toolhelp32 API, since
   // HeapWalk function is not available on those platforms.
   // However, experiments show that Heap32ListFirst/Heap32ListNext
   // functions unfortunately do NOT enumerate application's default
   // heap, when run on WinXP using Win95/98/Me compatibility modes.
   // (I have not run this test on actual systems themselves - as
   // opposed to using compatibility mode on XP). So far, I have
   // found no explanation of this effect, although this may change
   // in the future.
   //
   // Therefore, we implement the heap search as a 2-step process:
   // First, a flat search of the application's whole address space
   // (0x1000 - 0x7ffffff) is performed, starting at the default
   // heap location, wrapping around, and searching up to
   // application's HMODULE address. If that procedure fails, then
   // as a "double-check" action, we search the heaps, enumerated
   // by Heap32ListFirst/Heap32ListNext.

   // STEP 1: flat search of the application's address space.
   TRACE("Starting flat search of address space...");

   SYSTEM_INFO sysInfo;
   GetSystemInfo(&sysInfo);
   TRACE2("Memory page size: %d bytes", sysInfo.dwPageSize);

   HANDLE heap = GetProcessHeap();
   DWORD lastAddr = 0x80000000 - dataSize;
   for (DWORD* p = (DWORD*)heap; p < (DWORD*)lastAddr; p++)
   {
    if ((DWORD)p == (DWORD)data) continue; // don't compare with itself
    try
    {
     if (memcmp(p, data, dataSize) == 0) return p;
     p++;
    }
    catch (...)
    {
     // apparently, we cannot read this page
     // skip to the next page then.
     TRACE2("Memory read failed at %08x. Skipping to next page", (DWORD)p);
     p = (DWORD*)(((DWORD)p % sysInfo.dwPageSize + 1) * sysInfo.dwPageSize);
    }
   }

   // wrap-around and search from the beginning
   HMODULE hMod = GetModuleHandle(NULL);
   for (p = (DWORD*)0x1000; p < (DWORD*)hMod; p++)
   {
    if ((DWORD)p == (DWORD)data) continue; // don't compare with itself
    try
    {
     if (memcmp(p, data, dataSize) == 0) return p;
     p++;

    }
    catch (...)
    {
     // apparently, we cannot read this page
     // skip to the next page then.
     TRACE2("Memory read failed at %08x. Skipping to next page", (DWORD)p);
     p = (DWORD*)(((DWORD)p % sysInfo.dwPageSize + 1) * sysInfo.dwPageSize);
    }
   }

   TRACE("Flat address space search failed.");

   // STEP 2: use Toolhelp API.
   DWORD processId = GetCurrentProcessId();
   HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, processId);

   int i=0;
   HEAPLIST32 heapInfo;
   ZeroMemory(&heapInfo, sizeof(HEAPLIST32));
   heapInfo.dwSize = sizeof(HEAPLIST32);

   if (Heap32ListFirst(snap, &heapInfo))
   {
    do
    {
     TRACE2("Searching heap #%d...", i);
     TRACE2("Heap flags: %08x", heapInfo.dwFlags);
     if (heapInfo.dwFlags & HF32_DEFAULT) TRACE("(Default process heap)");
     DWORD* p = SearchHeap9x(&heapInfo, data, dataSize);
     if (p != NULL) return p;
     i++;
    }
    while (Heap32ListNext(snap, &heapInfo));
   }
   // didn't find the data
   return NULL;
}
}

/* Searches specified heap for certain data: (NT/2000/XP) version */
DWORD* SearchHeapNT(HANDLE heap, DWORD* data, DWORD dataSize)
{
PROCESS_HEAP_ENTRY mem;
mem.lpData = NULL;

TRACE("Starting search using HeapWalk...");
HeapLock(heap);
while (HeapWalk(heap, &mem))
{
   if (mem.wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) continue;
   //TRACE2("heap element size: %d", mem.cbData);

   if (mem.cbData < dataSize) continue;
   int count = (mem.cbData - dataSize)/sizeof(DWORD) + 1;

   DWORD* p = (DWORD*)mem.lpData;
   for (int i=0; i<count; i++)
   {
    if (memcmp(p, data, dataSize) == 0)
    {
     HeapUnlock(heap);
     return p;
    }
    p++;
   }
}
// data not found
HeapUnlock(heap);
return NULL;
}

/* Searches specified heap for certain data: (95/98/Me) version */
DWORD* SearchHeap9x(HEAPLIST32* heapInfo, DWORD* data, DWORD dataSize)
{
HEAPENTRY32 mem;
ZeroMemory(&mem, sizeof(HEAPENTRY32));
mem.dwSize = sizeof(HEAPENTRY32);

TRACE("Starting search using Heap32First/Heap32Last...");
if (Heap32First(&mem, heapInfo->th32ProcessID, heapInfo->th32HeapID))
{
   do
   {
    if (mem.dwFlags & LF32_FREE) continue;
    //TRACE2("heap element size: %d", mem.dwBlockSize);
    //TRACE2("heap element addr: %08x", mem.dwAddress);

    //TRACE2("Heap handle: %08x", (DWORD)mem.hHandle);

    if (mem.dwBlockSize < dataSize) continue;
    int count = (mem.dwBlockSize - dataSize)/sizeof(DWORD) + 1;

    DWORD* p = (DWORD*)mem.dwAddress;
    for (int i=0; i<count; i++)
    {
     if (memcmp(p, data, dataSize) == 0) return p;
     p++;
    }
   }
   while (Heap32Next(&mem));
}
return NULL;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值