典型的なmalloc
(x86-64 プラットフォームおよび Linux OS の場合) は、最初に単純にミューテックスをロックし、完了したら解放しますか? それとも、ロックの競合が減少するように、より細かいレベルでより巧妙な方法でミューテックスをロックしますか? 実際に 2 番目の方法で行う場合、どのように行うのでしょうか?
2 に答える
glibc 2.15
複数の割り当てアリーナを運営しています。各アリーナには独自のロックがあります。スレッドがメモリを割り当てる必要がある場合malloc()
、アリーナを選択してロックし、そこからメモリを割り当てます。
アリーナを選択するメカニズムはやや複雑で、ロックの競合を減らすことを目的としています。
/* arena_get() acquires an arena and locks the corresponding mutex.
First, try the one last locked successfully by this thread. (This
is the common case and handled with a macro for speed.) Then, loop
once over the circularly linked list of arenas. If no arena is
readily available, create a new one. In this latter case, `size'
is just a hint as to how much memory will be required immediately
in the new arena. */
これを念頭に置いて、malloc()
基本的には次のようになります(簡潔にするために編集):
mstate ar_ptr;
void *victim;
arena_lookup(ar_ptr);
arena_lock(ar_ptr, bytes);
if(!ar_ptr)
return 0;
victim = _int_malloc(ar_ptr, bytes);
if(!victim) {
/* Maybe the failure is due to running out of mmapped areas. */
if(ar_ptr != &main_arena) {
(void)mutex_unlock(&ar_ptr->mutex);
ar_ptr = &main_arena;
(void)mutex_lock(&ar_ptr->mutex);
victim = _int_malloc(ar_ptr, bytes);
(void)mutex_unlock(&ar_ptr->mutex);
} else {
/* ... or sbrk() has failed and there is still a chance to mmap() */
ar_ptr = arena_get2(ar_ptr->next ? ar_ptr : 0, bytes);
(void)mutex_unlock(&main_arena.mutex);
if(ar_ptr) {
victim = _int_malloc(ar_ptr, bytes);
(void)mutex_unlock(&ar_ptr->mutex);
}
}
} else
(void)mutex_unlock(&ar_ptr->mutex);
return victim;
このアロケータはと呼ばれptmalloc
ます。これは、Doug Leaによる以前の作業に基づいており、WolframGlogerによって保守されています。
Doug Lea がmalloc
使用した粗いロック (構成設定によってはロックなし) では、malloc
/ realloc
/へのすべての呼び出しfree
がグローバル ミューテックスによって保護されます。これは安全ですが、高度なマルチスレッド環境では効率が悪い場合があります。
ptmalloc3
最近のほとんどの Linux システムで使用されている GNU C ライブラリ (libc)のデフォルトの実装である には、 aix の回答malloc
で説明されているように、よりきめ細かい戦略があり、複数のスレッドがメモリを同時に安全に割り当てることができます。
nedmalloc
ptmalloc3
は、他のさまざまなアロケーターよりも優れたマルチスレッド パフォーマンスを主張する別の独立した実装です。どのように機能するのかはわかりませんし、明確なドキュメントもないようですので、ソース コードをチェックしてどのように機能するかを確認する必要があります。