apr内存池阅读笔记-申请内存

    xiaoxiao2021-12-04  30

    以注释的方式记录一下。 如有错误和建议欢迎留言。

    current_free_index:这个值表示的是分配器当前还能接收的内存大小。 max_free_index:这个值表示分配器最大可以接收的内存大小。 在整个内存池的设计上,是有父子层次结构的,并且分配器可以为多个内存池使用,考虑这样一种情况,多个内存池从一个分配器中向系统申请了大量内存,其中几个内存池生命周期结束被销毁,则节点都归还给分配器,此时只要分配器所属的内存池不释放就会有大量内存滞留在分配器中,这样显然是不合适的。上面2个值的作用就是限制分配器可以存放的内存数量,多余的内存都还给系统。      

    APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t in_size)

    从pool中分配size大小的内存。

    { apr_memnode_t *active, *node; //active指向当前内存池中活跃的(已使用)节点,node指向分配内存的节点。 void *mem; //返回的内存块指针 apr_size_t size, free_index; //将size内存对其,并判断合法性。 size = APR_ALIGN_DEFAULT(in_size); if (size < in_size) { if (pool->abort_fn) pool->abort_fn(APR_ENOMEM); return NULL; } active = pool->active;

    define APR_ALIGN_DEFAULT(size) APR_ALIGN(size, 8) 使in_size8字节对齐,方便后续的内存的计算。 ps:没想出来这个计算会有错误的结果。

    /* If the active node has enough bytes left, use it. */ //如果当前活跃的节点中足够,则从活跃的节点中分配内存返回。 if (size <= node_free_space(active)) { mem = active->first_avail; active->first_avail += size; return mem; } //判断active链表第二个节点是否有足够空闲内存(第二个是有可能比第一个空闲内存大的), //当active链表中的节点没有足够空闲内存时,从分配器中分配内存。 node = active->next; if (size <= node_free_space(node)) { list_remove(node); } else { if ((node = allocator_alloc(pool->allocator, size)) == NULL) { if (pool->abort_fn) pool->abort_fn(APR_ENOMEM); return NULL; } }

    active链表是以空闲内存递减的顺序排列的,但是第二个节点的空闲内存是可能大于第一个节点的。因为当第一个节点的空闲内存大于需要的内存时,函数直接返回需要的内存,此时并没有经过重新排序。当第二个节点满足所需内存或者从分配器中获取一个节点,都会对active链表重新排序。

    node->free_index = 0; //从节点中分配内存 mem = node->first_avail; node->first_avail += size; //把节点插入到active链表头 list_insert(node, active); pool->active = node; //计算节点剩余内存 free_index = (APR_ALIGN(active->endp - active->first_avail + 1, BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; active->free_index = (APR_UINT32_TRUNC_CAST)free_index; //将节点在active链表中插入合适的位置,链表是以空闲内存递减的。 node = active->next; if (free_index >= node->free_index) return mem; do { node = node->next; } while (free_index < node->free_index); list_remove(active); list_insert(active, node); return mem; }

    这里对free_index做些说明,这个值大小计算方式与节点中的index一致,看源码可以知道这个值主要的用途就是作为active链表排序时的依据,可以提高排序时的效率。如果以字节级别的大小来排序,可以想象这个排序速度会变的很慢,同样越粗略的排序也会造成更多的内存浪费,这应该是设计时做的一个取舍。         

    static APR_INLINE apr_memnode_t *allocator_alloc(apr_allocator_t *allocator, apr_size_t in_size)

    内存池分配的系统内存,实际是由分配器向系统申请的,并且在释放时也是先放回分配器中,然后一起返回给系统。

    { apr_memnode_t *node, **ref;//node:返回的节点 apr_uint32_t max_index; apr_size_t size, i, index; //size内存对其,使其不小于最小可分配内存。 size = APR_ALIGN(in_size + APR_MEMNODE_T_SIZE, BOUNDARY_SIZE); if (size < in_size) { return NULL; } if (size < MIN_ALLOC) size = MIN_ALLOC; //将size转换成free索引 index = (size >> BOUNDARY_INDEX) - 1; if (index > APR_UINT32_MAX) { return NULL; }

    将in_size计算成free数组索引,MIN_ALLOC是分配的最小内存,就是free[1].index的大小。

    if (index <= allocator->max_index) { #if APR_HAS_THREADS if (allocator->mutex) apr_thread_mutex_lock(allocator->mutex); #endif /* APR_HAS_THREADS */ //从free[index]开始寻找合适的节点,直到index==max_index。 max_index = allocator->max_index; ref = &allocator->free[index]; i = index; while (*ref == NULL && i < max_index) { ref++; i++; }

    当index小于等于allocator->max_index,即在当前数组中有存在满足需求的节点。while就是在数组中寻找满足的节点。代码中ref是二级指针,ref++相当于i++,*ref相当于free[i]。

    if ((node = *ref) != NULL) { //当得到的节点是当前最大节点链表中的最后一个时,寻找除这个节点之外最大可用的节点。 if ((*ref = node->next) == NULL && i >= max_index) { do { ref--; max_index--; } while (*ref == NULL && max_index > 0); allocator->max_index = max_index; }

    当取得的节点为free[max_index]中的最后一个时,需要调整allocator->max_index的值。

    //调整current_free_index值 allocator->current_free_index += node->index + 1; if (allocator->current_free_index > allocator->max_free_index) allocator->current_free_index = allocator->max_free_index; #if APR_HAS_THREADS if (allocator->mutex) apr_thread_mutex_unlock(allocator->mutex); #endif /* APR_HAS_THREADS */ //返回节点。 node->next = NULL; node->first_avail = (char *)node + APR_MEMNODE_T_SIZE; return node; } #if APR_HAS_THREADS if (allocator->mutex) apr_thread_mutex_unlock(allocator->mutex); #endif /* APR_HAS_THREADS */ } else if (allocator->free[0]) { #if APR_HAS_THREADS if (allocator->mutex) apr_thread_mutex_lock(allocator->mutex); #endif /* APR_HAS_THREADS */ //在free[0]中找一个满足的节点 ref = &allocator->free[0]; while ((node = *ref) != NULL && index > node->index) ref = &node->next; //找到满足的节点,返回节点。 if (node) { *ref = node->next; allocator->current_free_index += node->index + 1; if (allocator->current_free_index > allocator->max_free_index) allocator->current_free_index = allocator->max_free_index; #if APR_HAS_THREADS if (allocator->mutex) apr_thread_mutex_unlock(allocator->mutex); #endif /* APR_HAS_THREADS */ node->next = NULL; node->first_avail = (char *)node + APR_MEMNODE_T_SIZE; return node; }

    当index>max_index时先从free[0]中寻找能满足的节点,如果依然不存在则从系统中申请。

    #if APR_HAS_THREADS if (allocator->mutex) apr_thread_mutex_unlock(allocator->mutex); #endif /* APR_HAS_THREADS */ } //如果未找到满足的节点,则向系统申请内存产生一个节点返回。 #if APR_ALLOCATOR_USES_MMAP if ((node = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) #else if ((node = malloc(size)) == NULL) #endif return NULL; node->next = NULL; node->index = (APR_UINT32_TRUNC_CAST)index; node->first_avail = (char *)node + APR_MEMNODE_T_SIZE; node->endp = (char *)node + size; return node; }
    转载请注明原文地址: https://ju.6miu.com/read-680362.html

    最新回复(0)