Talloc内存池使用教程——(5)内存池

来源:互联网 发布:乐乎网页版 编辑:程序博客网 时间:2024/06/05 20:47

Talloc内存池使用教程——(5)内存池

内存池

申请一块新的内存是一个昂贵的操作,在大型程序的一次计算中有可能包含了成千上万次的malloc()调用,而每一次调用有可能只申请很小的一块内存。这可能导致应用程序慢到不可接受的程度。通过使用内存池,我们可以有效的减少malloc次数,来避免程序运行效率的降低。

一个内存池是一块固定大小的预申请好的内存空间。如果我们需要申请新的内存,我们将从内存池中拿到所需的内存空间,而不是从系统请求一块新的内存。这是通过创建一个指向预申请内存空间区域内的指针来实现的。这样的内存池不能重新分配内存空间,因为这将改变它的位置——原来指向它内部的指针将变为无效指针。因此,一个内存池需要很好的估计它所需要的内存空间。

Talloc库包含了自行实现的内存池,它对于开发者非常易懂。在初始化一个内存池context时,唯一要做的是使用talloc_pool()函数——这个函数也可以被其他任意的context使用。

根据下面的几个talloc内存池属性,使用内存池重构现有代码来获得性能提升将会十分简单:

  • 如果我们从一个内存池中申请内存,它将从内存池中拿走你需要的内存数量。
  • 如果一个context是内存池的子context,它将使用内存池的空间。
  • 如果内存池的剩余空间不够,它将创建一个新的非内存池context,独立于内存池之外。
/* 为内存池申请1KiB内存 */TALLOC_CTX *pool_ctx = talloc_pool(NULL, 1024);/* 从内存池中取走512B, 内存池中还剩下512B */void *ptr = talloc_size(pool_ctx, 512);/* 1024B > 512B, 这将在内存池之外创建一个新的talloc chunk */void *ptr2 = talloc_size(ptr, 1024);/* 内存池中还有512可用字节,这将从中再取走200B. */void *ptr3 = talloc_size(ptr, 200);/* 这将销毁context 'ptr3' 但是内存并没有被释放, 内存池中可用的内存大小将会增加到 512B. */talloc_free(ptr3);/* 这将同时释放 'pool_ctx' 和 'ptr2' 的内存. */talloc_free(pool_ctx);

上面的例子非常易懂,但是有一个大问题要牢记。如果一个talloc内存池的子节点更改了它的父节点,整块内存池将不会释放,直到这个子节点被释放。因此,我们在过继内存池的子节点的时候必须非常小心。

TALLOC_CTX *mem_ctx = talloc_new(NULL);TALLOC_CTX *pool_ctx = talloc_pool(NULL, 1024);struct foo *foo = talloc(pool_ctx, struct foo);/* mem_ctx 不在内存池中 */talloc_steal(mem_ctx, foo);/* pool_ctx 被标记已经被释放, 但这块内存并没有被释放, 再次访问pool_ctx这块内存将产生一个错误 */talloc_free(pool_ctx);/* 这时才会释放pool_ctx的内存. */talloc_free(mem_ctx);

一般来说,把我们需要的内存拷贝出来而不是过继talloc内存,能够避免这个问题。如果我们不需要保留talloc context名称(用来保存数据类型),我们可以通过使用talloc_memdup()来做到这一点。

然而,从内存池中拷贝数据有可能会抵消内存池所带来的性能提升,这取决于拷贝内存的大小。因此,如果我们选择这么做,应当使用profile工具来优化代码。一般来说,黄金法则是:如果我们需要过继一个内存池context,那我们就不应该使用内存池context。

0 0
原创粉丝点击