首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网络技术 > 网络基础 >

从Entry Point到main函数调用(三):heap_init

2012-12-19 
从Entry Point到main函数调用(3):_heap_init_heap_init在(1)中提到过该函数用于分配一个堆。这个堆是动态创

从Entry Point到main函数调用(3):_heap_init
_heap_init

在(1)中提到过该函数用于分配一个堆。这个堆是动态创建的私有堆,与系统为进程分配的默认堆不同。进程启动时,系统会在进程虚拟地址空间中创建一个堆,即为进程的默认堆。默认堆的创建和回收均由系统来完成。除了默认堆,进程中还可以存在若干个私有堆。私有堆可以由进程动态创建,并且在此基础上进行内存分配、释放等操作。

?

_heap_init函数本质上是调用了HeapCreate函数,HeapCreate也是kernel32.dll提供的API。在CRT0.c 中对_heap_init 的调用为:

#ifdef _MT        if ( !_heap_init(1) )               /* initialize heap */#else  /* _MT */        if ( !_heap_init(0) )               /* initialize heap */#endif  /* _MT */            fast_error_exit(_RT_HEAPINIT);  /* write message and die */ 

这里的_MT表示是否使用运行时库(CRT)的多线程静态版本:(测试环境VC6)

如果在VS中创建一个MFC APP,会加上 int __cdecl _heap_init (int mtflag){ // Initialize the "big-block" heap first. if ( (_crtheap = HeapCreate( mtflag ? 0 : HEAP_NO_SERIALIZE, BYTES_PER_PAGE, 0 )) == NULL ) return 0; // Pick a heap, any heap __active_heap = __heap_select(); if ( __active_heap == __V6_HEAP ) { // Initialize the small-block heap if (__sbh_heap_init(MAX_ALLOC_DATA_SIZE) == 0) { HeapDestroy(_crtheap); return 0; } } else if ( __active_heap == __V5_HEAP ) { if ( __old_sbh_new_region() == NULL ) { HeapDestroy( _crtheap ); return 0; } } return 1;}

在本例中,相当于执行了:

int __cdecl _heap_init (int mtflag){        //  Initialize the "big-block" heap first.        if ( (_crtheap = HeapCreate(  HEAP_NO_SERIALIZE, BYTES_PER_PAGE, 0 )) == NULL )            return 0;        // Pick a heap, any heap        __active_heap = __heap_select();        return 1;}
?

代码中第四行的_crtheap 是定义在 heapinit.c 开头处的一个全局变量。它表示当 HeapCreate 运行成功之后,返回一个指向新分配堆的句柄。HeapCreate 函数原型如下:

HANDLE WINAPI HeapCreate(  __in  DWORD flOptions,  __in  SIZE_T dwInitialSize,  __in  SIZE_T dwMaximumSize);

第一个参数flOptions 是 HEAP_NO_SERIALIZE。HEAP_NO_SERIALIZE 表示可以对堆采用非序列化的访问。采用序列化的访问可以避免在多个线程在同一块堆上分配内存时产生冲突,这有点儿加上一把同步锁的意思。但如果指定了HEAP_NO_SERIALIZE ,则这种串行访问的方式就被去除掉了。也就是说,不同的线程可以同时用 Handle 去操作同一个堆,这显然容易导致堆内存的破坏。

#define BYTES_PER_PARA 16#define PARAS_PER_PAGE 256 // tunable value#define BYTES_PER_PAGE (BYTES_PER_PARA * PARAS_PER_PAGE)

这样计算出来 16 * 256 = 16^3 =? 0x1000 bytes

?

第三个参数dwMaximumSize指明了堆的最大字节数。dwMaximumSize = 0 时,被创建的堆可以在需要的时候被扩建,是一个可增长堆,理论上这个堆的最大大小仅仅受限于可用的内存大小。当dwMaximumSize !=0 时,那么堆的大小是固定的,并且不能大于dwMaximumSize指定的范围。

?

更详细的可以参考:http://msdn.microsoft.com/en-us/library/aa366599%28VS.85%29.aspx

?

?

当HeapCreat 执行完毕后,会接着调用__heap_select 函数。__heap_select 负责为之前创建的堆指定类型,并且存放在全局变量 __active_heap 中,__active_heap 会影响到后续 malloc 时的内存分配方式。

?

WINHEAP.H头文件中定义了三种堆:

//  Heap-selection constants#define __SYSTEM_HEAP           1#define __V5_HEAP               2#define __V6_HEAP               3

对于WIN2K向上的所有系统,都会将堆指定为 __SYSTEM_HEAP 类型,因为在__heap_select 函数中有如下实现:

OSVERSIONINFO osvi;// First, check the OS for NT >= 5.0osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);if ( GetVersionEx(&osvi) )    if ( (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) && (osvi.dwMajorVersion >= 5) )        return __SYSTEM_HEAP;

至于__V5_HEAP、__V6_HEAP暂时不做深究。

?

?

1 楼 RednaxelaFX 2011-05-19   话说邦邦你是为啥要玩这些东西的…? 2 楼 driftcloudy 2011-05-19   RednaxelaFX 写道话说邦邦你是为啥要玩这些东西的…?
也许我想对某些要注册或者收费的东东进行破坏性活动吧...
虽然还木有搞定过正式的啥程序
我觉得这些东西玩了之后大有裨益啊~ 3 楼 RednaxelaFX 2011-05-19   也就是完全兴趣驱动? 4 楼 driftcloudy 2011-05-19   RednaxelaFX 写道也就是完全兴趣驱动?
算是吧...

热点排行