在程序开发中,堆和栈是最常使用的两个内存区,在Linux下栈分为用户栈和内核栈,内核栈具有固定大小,而用户栈可以通过ulimit来设定,最大8M。
堆具有很大的灵活性,程序员可以根据需要获取任意大小的内存(只只是相对于栈来说,对于32位机,它最大能分配2G多的虚拟地址空间)。malloc/free就是提供给程序员来在堆上分配内存的接口。在堆上分配内存,为什么会产生额外的开销?这些开销是多少? 先来看看堆分配的主要数据结构:
typedef struct free_list {
spin_lock_t lock;/* spin lock for mutual exclusion */
header_t head;/* head of free list for this size */
#ifdef DEBUG
int in_use; 
 /* # mallocs - # frees */
#endif DEBUG
} *free_list_t;
typedef union header {
union header *next;
struct free_list *fl;
} *header_t;
#define MIN_SIZE 8/* minimum block size */
#define NBUCKETS 29
static struct free_list malloc_free_list[NBUCKETS];
通过以上主要的数据结构,我们了解到,malloc额外内存开销主要是,一个malloc_free_list数组(8×29byte),和每malloc一次占用4byte,这样对于小块内存请求来说,效率就比较低。
接下来再分别看看malloc和free的处理流程:
malloc处理流程
1. 首先给size增加sizeof(union header),这是为了把头和待分配的内存块合在一起使用的一个小技巧。
2. 用size去匹配该属于哪个malloc_free_list槽中,malloc_free_list最小8byte,然后每个递增一倍。
3. 匹配上插槽后,然后看这个插槽中有没有空闲的块供分配,如果没有,就调用more_memory来添加,more_memory一次最少需要添加一页。
4.然后就取出freelist中第一个值,free指针下移,返回header+sizeof(union header),这就是供使用的内存。
5.而header中保存的是free list指针,这样当free的时候,就能找到相应的插槽,而不用知道需要释放的内存大小,这也是一个小技巧,屏蔽了额外的开销。
free处理流程
1. free的地址前移sizeof(union header),这样找到freelist指针。
2. 然后把这个单元添加进相应插槽的freelist链表中。
                  
                  
                  
                  
                            
本文深入解析了堆内存分配的开销来源,包括malloc/free处理流程及其内部数据结构,揭示了其效率较低的原因,并详细阐述了如何在小块内存请求中优化性能。
          
      
          
                
                
                
                
              
                
                
                
                
                
              
                
                
              
            
                  
					853
					
被折叠的  条评论
		 为什么被折叠?
		 
		 
		
    
  
    
  
            


            