對malloc的原始碼剖析源於我自己實現的共享記憶體分配器,使用buddy演算法和紅黑樹結構實現對共享記憶體的分配**管理,對其效能進行測試的時候,發現效能只有malloc的1/3~1/2,原本以為自己的實現效能應該比malloc高的,結果出乎意外,這讓我產生窺探dlmalloc原始碼的好奇心,為此,找到http: //www.malloc.de/malloc/ptmalloc2.tar.gz的源**進行分析,該版本在多執行緒環境中其效能較高,具體見裡面的readme說明
先拿到malloc入手,去除不必要的巨集,其原始碼如下
void* malloc(size_t bytes)
else
#endif
}
if(!victim) return 0;
} else
(void)mutex_unlock(&ar_ptr->mutex);
return chunk2mem(victim); // 將chunk轉換成指標
}
從上面的原始碼知,malloc的實現很簡單:
1、根據請求的bytes大小進行調整
2、獲取適當的arena
3、從arena中獲取chunk
下面看一下幾個重要的巨集及函式
// pad request bytes into a usable size, return non-zero on overflow
// 對req增加必要的cookie資訊所需要的長度然後進行對齊,當溢位時返回1
#define request2size(req, nb) /
((nb = (req) + (size_sz + malloc_align_mask)),/
((long)nb <= 0 || nb < (internal_size_t) (req) /
? (__set_errno (enomem), 1) /
: ((nb < (minsize + malloc_align_mask) /
? (nb = minsize) : (nb &= ~malloc_align_mask)), 0)))
// 獲取arena並對其上鎖,首先查詢被該執行緒所占用的arena,如果獲取不到,則對arena鍊錶進行搜尋,如果仍沒有可用的arean,則建立乙個新的,建立新的arena時,第二個引數只是用於提示新的arena需要立即分配多大的空間
#define arena_get(ptr, size) do else /
ptr = arena_get2(ptr, (size)); /
} while(0)
arena_get2從迴圈的arena鍊錶中找合適的arena,如果沒有找到,則建立新的arena
static arena * internal_function arena_get2(arena *a_tsd, size_t size)
}
// 從arena迴圈鍊錶中搜尋可用的arena
repeat:
do
a = a->next;
} while(a != a_tsd);
// 從arena迴圈鍊錶中仍沒有找到可用的arena,如果不能獲得list_lock,則重新嘗試
if(mutex_trylock(&list_lock))
(void)mutex_unlock(&list_lock);
// 沒有現成可用的arena,所以建立乙個新的arena
// 首先是建立乙個heap
h = new_heap(size + (sizeof(*h) + sizeof(*a) + malloc_alignment));
if(!h)
// 初始化heap的arena資訊
a = h->ar_ptr = (arena *)(h+1);
for(i=0; inext = null;
a->size = h->size;
arena_mem += h->size;
// 初始化該heap的mutex, lock mutex
tsd_setspecific(arena_key, (void_t *)a);
mutex_init(&a->mutex);
i = mutex_lock(&a->mutex); /* remember result */
// 設定heap的第乙個chunk,並且要正確地對齊
ptr = (char *)(a + 1);
misalign = (unsigned long)chunk2mem(ptr) & malloc_align_mask;
if (misalign > 0)
ptr += malloc_alignment - misalign;
top(a) = (mchunkptr)ptr;
set_head(top(a), (((char*)h + h->size) - ptr) | prev_inuse);
// 把新的arena新增到arena鍊錶中
(void)mutex_lock(&list_lock);
a->next = main_arena.next;
main_arena.next = a;
(void)mutex_unlock(&list_lock);
if(i) /* locking failed; keep arena for further attempts later */
return 0;
thread_stat(++(a->stat_lock_loop));
return a;
}
static mchunkptr internal_function chunk_alloc(arena *ar_ptr, internal_size_t nb)
if (victim != q) // 從bin中獲取到chunk,返回
// 從上面的兩個bin中沒有找到合適的chunk,則需要從其餘的bin中進行查詢
idx += 2;
}
else
else if (remainder_size >= 0) // 完全匹配
}
++idx;
}
// 利用上次拆分剩餘的chunk
if ( (victim = last_remainder(ar_ptr)->fd) != last_remainder(ar_ptr))
// 上次拆分剩餘的chunk的大小正好合適,把該chunk分配出去,把它從remainder鍊錶中去掉
clear_last_remainder(ar_ptr);
if (remainder_size >= 0) // remainder鍊錶不為空,則簡單把拆分後剩下的chunk進行設定
// 否則需要把拆分後剩下的chunk放到remainder鍊錶中
frontlink(ar_ptr, victim, victim_size, remainder_index, bck, fwd);
}
// 如果還有可能的非空並且足夠大的塊,從其它bin中進行查詢最匹配的chunk
if ( (block = idx2binblock(idx)) <= binblocks(ar_ptr))
}
// 對每乙個可能的非空塊
for (;;)
else if (remainder_size >= 0) // 使用該chunk
}
bin = next_bin(bin);
} while ((++idx & (binblockwidth - 1)) != 0);
// 清除block標識位
do
--startidx;
q = prev_bin(q);
} while (first(q) == q);
// 獲取下乙個可能的非空塊
if ( (block <<= 1) <= binblocks(ar_ptr) && (block != 0) )
}
else
break;
}
}
// 嘗試使用top chunk,要求要有乙個remainder,從而確保top總是存在的
if ( (remainder_size = chunksize(top(ar_ptr)) - nb) < (long)minsize)
victim = top(ar_ptr);
set_head(victim, nb | prev_inuse);
top(ar_ptr) = chunk_at_offset(victim, nb);
set_head(top(ar_ptr), remainder_size | prev_inuse);
check_malloced_chunk(ar_ptr, victim, nb);
return victim;
}
原始碼剖析 Hashtable 原始碼剖析
hashtable同樣是基於雜湊表實現的,同樣每個元素都是key value對,其內部也是通過單鏈表解決衝突問題,容量不足 超過了閾值 時,同樣會自動增長。hashtable也是jdk1.0引入的類,是執行緒安全的,能用於多執行緒環境中。hashtable同樣實現了serializable介面,它支...
python原始碼剖析 Python原始碼剖析
第頁共 頁python 原始碼剖析 物件機制 1.物件 在python 的世界中,一切都是物件,乙個整數是乙個物件,乙個字串也是 乙個物件,更為奇妙的是,型別也是乙個物件,整數型別是乙個物件,字串類 型也是乙個物件。從 年guido 在那個聖誕節揭開 python 世界的大幕開始,一直到現在,pyt...
Erlang hotwheels原始碼剖析
整體構架 janus transport sup 實質為transport,supervisor,client instance supervisor 每個tcp會話建立乙個transport程序來處理對應客戶端的請求。janus topman sup 實質為topman,worker,topic ...