簡體   English   中英

malloc 在多線程環境下如何工作?

[英]How does malloc work in a multithreaded environment?

典型的malloc (對於 x86-64 平台和 Linux 操作系統)是天真地在開始時鎖定互斥量並在完成時釋放它,還是以更聰明的方式在更精細的級別鎖定互斥量,從而減少鎖爭用並發調用? 如果確實是第二種方式,它是如何做到的?

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都受全局互斥鎖的保護。 這是安全的,但在高度多線程環境中可能效率低下。

ptmalloc3是目前大多數Linux系統上使用的GNU C庫(libc)中的默認malloc實現,它具有更細粒度的策略,如aix的答案中所述 ,它允許多個線程同時安全地分配內存。

nedmalloc是另一個獨立的實現,它聲稱比ptmalloc3和其他各種分配器具有更好的多線程性能。 我不知道它是如何工作的,似乎沒有任何明顯的文檔,所以你必須檢查源代碼,看看它是如何工作的。

除了@NPE提到的ptmalloc ,還有Google提供的tcmalloc ,在某些場景下,經測試運行速度略快於ptmalloc (例如:執行10^6次malloc()並釋放時) ).

它使用全局堆和每線程堆,以便每個線程都可以使用全局堆。 全局堆上只有互斥鎖,每線程堆上沒有。 對於每個單獨的線程,他們可以從全局堆中提取存儲並釋放該存儲,以便該存儲進入每個線程堆。

每個線程堆都由單獨的線程擁有。 除非情況不平衡,否則線程會將存儲移回全局堆。

代碼實現在這里: https://github.com/google/tcmalloc

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM