如果您有一个动态分配的缓冲区,它在运行时以无法预测的方式(例如 vector 或字符串)改变其大小,则一种优化其分配的方法是仅以2的幂(或其他一些边界/阈值),并保留多余的空间。这有助于分摊寻找新的可用内存和复制数据的成本,但要花一点额外的内存。例如,许多C++ STL容器的接口(interface)规范(保留,调整大小,修剪)都考虑了这种方案。

我的问题是在Linux 3.0 x86_64,GLIBC 2.13,GCC 4.6(Ubuntu 11.10)上的malloc/realloc/free内存管理器的默认实现是否进行了这样的优化?

void* p = malloc(N);
... // time passes, stuff happens
void* q = realloc(p,M);

换句话说,对于N和M的哪个值(或在其他情况下),p == q?

最佳答案

来自http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=12d2211b0d6603ac27840d6f629071d1c78586fe;hb=HEAD的glibc主干中的realloc实现

首先,如果内存是通过mmap()而不是sbrk()获得的,那么glibc malloc会对大型请求执行此操作,默认情况下> = 128 kB IIRC:


   if (chunk_is_mmapped(oldp))
   {
     void* newmem;

 #if HAVE_MREMAP
     newp = mremap_chunk(oldp, nb);
     if(newp) return chunk2mem(newp);
 #endif
     /* Note the extra SIZE_SZ overhead. */
     if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
     /* Must alloc, copy, free. */
     newmem = public_mALLOc(bytes);
     if (newmem == 0) return 0; /* propagate failure */
     MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
     munmap_chunk(oldp);
     return newmem;
   }

(Linux具有mremap(),因此实际上就是这样做的)。

对于较小的请求,我们在下面几行
newp = _int_realloc(ar_ptr, oldp, oldsize, nb);

_int_realloc在此处需要复制粘贴很大,但是您会在上面链接的第4221行开始找到它。 AFAICS,它不会像C++ std::vector可以,但是确切地分配用户请求的数量(四舍五入到下一个块边界+对齐内容,依此类推)。

我想这个想法是,如果用户希望此大小增加2的因子(或任何其他常数因子的增加,以确保多次调整大小时的对数效率),那么用户可以在由C库。

08-06 00:41