如前面所提到的,
Malloc类集使用模板类ACE_Malloc来提供内存管理。如图3-2所示,ACE_Malloc模板需要两个参数(一个是内存池,一个是池锁),以产生我们的分配器类。

图
3-2 ACE_Malloc模板参数示意图 3.2.1 ACE_Malloc工作原理ACE_Malloc
从传入的内存池中“获取”内存,应用随即通过ACE_Malloc类接口来分配(malloc())内存。由底层内存池返回的内存又在ACE的“chunk”(大块)中被返回给ACE_Malloc类。ACE_Malloc类使用这些内存chunk来给应用开发者分配较小的内存block(块)。如图3-3所示:

图
3-3 ACE_Malloc的工作原理
当应用请求内存
block时,ACE_Malloc类会检查在它从内存池中获取的chunk中,是否有足够的空间来分配所需的block。如果未能发现有足够空间的chunk,它就会要求底层内存池返回一个更大的chunk,以满足应用对内存block的请求。当应用发出free()调用时,ACE_Malloc不会把所释放的内存返还给内存池,而是由它自己的空闲表进行管理。当ACE_Malloc收到后续的内存请求时,它会使用空闲表来查找可返回的空block。因而,在使用ACE_Malloc时,如果只发出简单的malloc()和free()调用,从OS分配的内存数量将只会增加,不会减少。ACE_Malloc类还含有一个remove()方法,用于发出请求给内存池,将内存返还给OS。该方法还将锁也返还给OS。3.2.2 使用ACE_Malloc
ACE_Malloc
类的使用很简单。首先,用你选择的内存池和锁定机制实例化ACE_Malloc,以创建分配器类。随后用该分配器类实例化一个对象,这也就是你的应用将要使用的分配器。当你实例化分配器对象时,传给构造器的第一个参数是一个字符串,它是你想要分配器对象使用的底层内存池的“名字”。将正确的名字传递给构造器非常重要,特别是如果你在使用共享内存的话。否则,分配器将会为你创建一个新的内存池。如果你在使用共享内存池,这当然不是你想要的,因为你根本没有获得共享。为了方便底层内存池的共享(重复一次,如果你在使用共享内存的话,这是很重要的),
ACE_Malloc类还拥有一个映射(map)类型接口:可被给每个被分配的内存block一个名字,从而使它们可以很容易地被在内存池中查找的另一个进程找到。该接口含有bind()和find()调用。bind()调用用于给由malloc()调用返回给ACE_Malloc的block命名。find()调用,如你可能想到的那样,用于查找与某个名字相关联的内存。在实例化
ACE_Malloc模板类时,有若干不同的内存池类可用(如表3-2所示)。这些类不仅可用于分配在进程内使用的内存,也可以用于分配在进程间共享的内存池。这也使得为何ACE_Malloc模板需要通过锁定机制来实例化显得更清楚了。当多个进程访问共享内存池时,该锁保证它们不会因此而崩溃。注意即使是多个线程在使用分配器,也同样需要提供锁定机制。表
3-2列出了各种可用的内存池:
|
池名 |
宏 |
描述 |
|
ACE_MMAP_Memory_Pool |
ACE_MMAP_MEMORY_POOL |
使用 |
|
ACE_Lite_MMAP_Memory_Pool |
ACE_LITE_MMAP_MEMORY_POOL |
使用 |
|
ACE_Sbrk_Memory_Pool |
ACE_SBRK_MEMORY_POOL |
使用 |
|
ACE_Shared_Memory_Pool |
ACE_SHARED_MEMORY_POOL |
使用系统 V |
|
Memory_Pool |
内存可在进程间共享。 | |
|
ACE_Local_Memory_Pool |
ACE_LOCAL_MEMORY_POOL |
通过 C++的new和delete操作符创建局部内存池。该池不能在进程间共享。 |
表
3-2 可用的内存池
下面的例子通过共享内存池使用
ACE_Malloc类(该例使用ACE_SHARED_MEMORY_POOL来做演示,但表3-2中的任何支持内存共享的内存池都可以被使用)。该例创建服务器进程,该进程创建内存池,再从池中分配内存。然后服务器使用从池中分配的内存来创建它想要客户进程“拾取”的消息。其次,它将名字绑定(
bind)到这些消息,以使客户能使用相应的find操作来查找服务器插入池中的消息。客户在开始运行后创建它自己的分配器,但是使用的是同一个内存池。这是通过将同一个名字传送到分配器的构造器来完成的,然后客户使用
find()调用来查找服务器插入的消息,并将它们打印给用户看。
