malloc()
c 語言的malloc是glibc函數,其實際對應的系統調用是brk()函數(其實是syscall 1)。glibc對brk系統調用進行封裝,而後抽象出malloc函數,提供給linux開發者使用。brk函數對應的是堆操做;linux
進程的空間 = 系統空間+用戶空間(棧:局部變量和函數參數,寄存器+堆:動態內存,開發者分配+.bss+data常量區+text代碼段)算法
32位系統只能尋址4G空間,64位則是128G; 編程
(1)new、delete 是操做符,只能在C++中使用。malloc、free是函數,能夠覆蓋,C、C++中均可以使用。
(2)new 自動計算須要分配的空間大小,能夠調用對象的構造函數,對應的delete調用相應的析構函數。malloc僅僅分配內存,free僅僅回收內存,並不執行構造和析構函數
(3)new 類型安全、返回的是某種數據類型指針,malloc 非類型安全、返回的是void指針。
TCMalloc
TCMalloc全稱Thread-Caching Malloc,即線程緩存的malloc,實現了高效的多線程內存管理,用於替代系統的內存分配相關的函數(malloc、free,new,new[]等)。TCMalloc是gperftools的一部分緩存
TCMalloc內存分配算法
按照所分配內存的大小,TCMalloc將內存分配分爲三類:安全
- 小對象分配,(0, 256KB]
- 中對象分配,(256KB, 1MB]
- 大對象分配,(1MB, +∞)
簡要介紹幾個概念,Page,Span,PageHeap:多線程
ThreadCache:每一個線程的單獨緩存,由FreeList按Size Class(8KB/16KB...256KB)存儲的空閒對象鏈表;線程內部取用回收不須要加鎖因此很快;函數
CentralCache: 全部線程的公用緩存,由 CentralFreeList按Size Class(8KB/16KB...256KB)存儲的空閒對象鏈表;供各個線程的 ThreadCache 取用,因此取用或回收對象是須要加鎖的;oop
PageHeap:CentralCache不夠時向 PageHeap申請一塊內存,PageHeap使用sbrk或mmap向系統申請新的內存以生成新的span;PageHeap內部根據內存塊(span)採起不一樣的緩存策略:128個 span之內,每一個 size 用鏈表緩存,超過128個 page 的 span,存儲與一個有序的 set 裏,PageHeap取用或釋放內存時須要加 spinlock,post
互斥和同步
同步:任務協調同步,好比 A 依賴 Bspa
互斥:訪問共享資源
互斥鎖(mutex)
上鎖(lock)和解鎖(unlock);原子性(原子操做)、惟一性、非繁忙等待(A 線程鎖定互斥量,則 B 線程試圖鎖時會被掛起即不佔用 cpu資源,直至互斥量解鎖喚醒B線程)
#include <pthread.h> #include <time.h> // 初始化一個互斥鎖。 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); // 對互斥鎖上鎖,若互斥鎖已經上鎖,則調用者一直阻塞, // 直到互斥鎖解鎖後再上鎖。 int pthread_mutex_lock(pthread_mutex_t *mutex); // 調用該函數時,若互斥鎖未加鎖,則上鎖,返回 0; // 若互斥鎖已加鎖,則函數直接返回失敗,即 EBUSY。 int pthread_mutex_trylock(pthread_mutex_t *mutex); // 當線程試圖獲取一個已加鎖的互斥量時,pthread_mutex_timedlock 互斥量 // 原語容許綁定線程阻塞時間。即非阻塞加鎖互斥量。 int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abs_timeout); // 對指定的互斥鎖解鎖。 int pthread_mutex_unlock(pthread_mutex_t *mutex); // 銷燬指定的一個互斥鎖。互斥鎖在使用完畢後, // 必需要對互斥鎖進行銷燬,以釋放資源。 int pthread_mutex_destroy(pthread_mutex_t *mutex); |
條件變量(同步)
條件變量用來自動阻塞一個線程,直 到某特殊狀況發生爲止
條件變量使用過程:1. 初始化:2. 等待條件成立3. 激活條件變量:4. 清除條件變量:
#include <pthread.h> // 初始化條件變量 int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr); // 阻塞等待 int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex); // 超時等待 int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex, const timespec *abstime); // 解除全部線程的阻塞 int pthread_cond_destroy(pthread_cond_t *cond); // 至少喚醒一個等待該條件的線程 int pthread_cond_signal(pthread_cond_t *cond); // 喚醒等待該條件的全部線程 int pthread_cond_broadcast(pthread_cond_t *cond); |
讀寫鎖
#include <pthread.h> // 初始化讀寫鎖 int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); // 申請讀鎖 int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock ); // 申請寫鎖 int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock ); // 嘗試以非阻塞的方式來在讀寫鎖上獲取寫鎖, // 若是有任何的讀者或寫者持有該鎖,則當即失敗返回。 int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); // 解鎖 int pthread_rwlock_unlock (pthread_rwlock_t *rwlock); // 銷燬讀寫鎖 int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); |
自旋鎖
鎖的持有時間比較短,或者說小於2次上下文切換的時間。
spinlock又稱自旋鎖,線程經過busy-wait-loop的方式來獲取鎖,任時刻只有一個線程可以得到鎖,其餘線程忙等待直到得到鎖
spinlock在多處理器多線程環境的場景中有很普遍的使用,通常要求使用spinlock的臨界區儘可能簡短,這樣獲取的鎖能夠儘快釋放,以知足其餘忙等的線程。Spinlock和mutex不一樣,spinlock不會致使線程的狀態切換(用戶態->內核態),可是spinlock使用不當(如臨界區執行時間過長)會致使cpu busy飆高。
信號量(同步和互斥)
信號量普遍用於進程或線程間的同步和互斥,信號量本質上是一個非負的整數計數器,它被用來控制對公共資源的訪問。
編程時可根據操做信號量值的結果判斷是否對公共資源具備訪問的權限,當信號量值大於 0 時,則能夠訪問,不然將阻塞。PV 原語是對信號量的操做,一次 P 操做使信號量減1,一次 V 操做使信號量加1。
#include <semaphore.h> // 初始化信號量 int sem_init(sem_t *sem, int pshared, unsigned int value); // 信號量 P 操做(減 1) int sem_wait(sem_t *sem); // 以非阻塞的方式來對信號量進行減 1 操做 int sem_trywait(sem_t *sem); // 信號量 V 操做(加 1) int sem_post(sem_t *sem); // 獲取信號量的值 int sem_getvalue(sem_t *sem, int *sval); // 銷燬信號量 int sem_destroy(sem_t *sem); |