SGI STL 的内存池是如何回收 chunk 内存的?

SGI STL 中, 没有使用的内存会以链表的方式挂载在 free_list 中, 如果 free_list 中有足够的内存, 那么直接返回. 但是内存的回收并不一定是按照内存的申请顺序来的, 这就导致链表的第一个并不一定是 chunk 的头部内存

而如果要回收 chunk 部分的内存, 必须要知道其 malloc() 回传的头部地址, 然后将其传给 free(). 虽然这个地址一定会在 free_list 中存在, 但是如何知道呢? 目前唯一能够想到的方法就是有一个动态的 void *[] 数组, 记录头部地址

因为在 chunk_alloc() 中, 如果出现 start_free == end_free 的情况, 在有足够内存的情况下, 也就是 malloc() 成功, start_freeend_free 都会被覆盖. 而 chunk_alloc() 函数中并没有任何操作是去记录原来的地址的

因此, 我查看了 STLport 5.2.1 中 allocators.cpp 的源码, 有关 chunk 内存的回收, 我找到这些代码 :

void __node_alloc_impl::_S_chunk_dealloc() {
  _Obj *__pcur = _S_chunks, *__pnext;
  while (__pcur != 0) {
    __pnext = __pcur->_M_next;
    __stlp_delete_chunck(__pcur);
    __pcur = __pnext;
  }
  _S_chunks = 0;
  _S_start_free = _S_end_free = 0;
  _S_heap_size = 0;
  memset(__REINTERPRET_CAST(char*, __CONST_CAST(_Obj**, &_S_free_list[0])), 0, _STLP_NFREELISTS * sizeof(_Obj*));
}

以及

void __node_alloc_impl::_S_chunk_dealloc() {
  // Note: The _Node_alloc_helper class ensures that this function
  // will only be called when the (shared) library is unloaded or the
  // process is shutdown.  It's thus not possible that another thread
  // is currently trying to allocate a node (we're not thread-safe here).
  //

  // Clear the free blocks and all freelistst.  This makes sure that if
  // for some reason more memory is allocated again during shutdown
  // (it'd also be really nasty to leave references to deallocated memory).
  _S_free_mem_blocks.clear();
  _S_heap_size      = 0;

  for (size_t __i = 0; __i < _STLP_NFREELISTS; ++__i) {
    _S_free_list[__i].clear();
  }

  // Detach list of chunks and free them all
  _Obj* __chunk = _S_chunks.clear();
  while (__chunk != 0) {
    _Obj* __next = __chunk->_M_next;
    __stlp_delete_chunck(__chunk);
    __chunk  = __next;
  }
}

一样的名称, 所以肯定是由 macro 进行选择

与 《STL 源码剖析》中相对应的 chunk_dealloc() 应该是第一段

在第一段中, 其实就是不断地去 __stlp_delete_chunck(__pcur); 但实际上这个函数只是调用 free() 或者 ::operator delete(), 对于 free_list 中每一小段内存都是用 free() 或者 ::operator delete(). 这好像是不可行的, 所以对此, 我写了一小段 demo :

#include <iostream>

using namespace std;
union x {
    x *next;
    char client_data[0];
};
int main(int argc, char *argv[]) {
    auto p {malloc(sizeof(x) * 2)};
    auto x_ptr1 {static_cast<x *>(p)};
    auto x_ptr2 {static_cast<x *>(p) + 1};
    free(x_ptr2);
    free(x_ptr1);
}

最终的结果就是 pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug
Terminated due to signal: ABORT TRAP (6)

所以这并不可行

想请教各位, SGI STL 最终是如何对 chunk 内存进行回收的?

阅读 3.4k
1 个回答
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题