典型的なmalloc
(x86-64プラットフォームおよびLinux OSの場合)は、最初に単純にmutexをロックして完了時に解放しますか、それともより巧妙な方法でより細かいレベルでmutexをロックしますか。ロックの競合が軽減されますか?それが実際に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による 以前の作業 に基づいており、Wolfram Glogerによって保守されています。
Doug Leaのmalloc
は、粗いロックを使用しました(または構成設定に応じて、ロックなし)。ここで、malloc
/realloc
/free
へのすべての呼び出しは、グローバルmutexによって保護されます。これは安全ですが、高度なマルチスレッド環境では非効率になる可能性があります。
ptmalloc3
は、最近のほとんどのLinuxシステムで使用されているGNU Cライブラリ(libc)のデフォルトのmalloc
実装)であり、よりきめ細かい aixの回答 で説明されているように、複数のスレッドがメモリを同時に安全に割り当てることができる戦略。
nedmalloc
は、ptmalloc3
およびその他のさまざまなアロケータよりも優れたマルチスレッドパフォーマンスを主張する別の独立した実装です。私はそれがどのように機能するのかわかりませんし、明確なドキュメントもないようです。そのため、ソースコードをチェックして、どのように機能するかを確認する必要があります。