摘要:內(nèi)存池的作用直接使用系統(tǒng)調(diào)用會有如下弊端頻繁分配內(nèi)存時會產(chǎn)生大量內(nèi)存碎片頻繁分配內(nèi)存增加系統(tǒng)調(diào)用開銷容易造成內(nèi)存泄漏內(nèi)存池是預先申請一定數(shù)量的,大小相等的內(nèi)存塊作為預備使用當需要時向內(nèi)存池分出一部分內(nèi)存,若內(nèi)存塊不夠使用時再向系統(tǒng)申請新的內(nèi)
內(nèi)存池的作用:
直接使用系統(tǒng)調(diào)用malloc會有如下弊端:
頻繁分配內(nèi)存時會產(chǎn)生大量內(nèi)存碎片
頻繁分配內(nèi)存增加系統(tǒng)調(diào)用開銷
容易造成內(nèi)存泄漏
內(nèi)存池是預先申請一定數(shù)量的,大小相等的內(nèi)存塊作為預備使用;當需要時向內(nèi)存池分出一部分內(nèi)存,若內(nèi)存塊不夠使用時再向系統(tǒng)申請新的內(nèi)存塊,下面就swoole的swMemoryGlobal內(nèi)存池作為分析例子swoole swMemoryPool 數(shù)據(jù)結構設計
swMemoryGlobal是swoole內(nèi)存池實現(xiàn)一種方式,學習內(nèi)存池主要是要掌握其數(shù)據(jù)結構的設計,memoryGlobal實現(xiàn)如下:
// src/memory/MemoryGlobal.c typedef struct _swMemoryPool { void *object; // 指向swMemoryGlobal指針 void* (*alloc)(struct _swMemoryPool *pool, uint32_t size); // 分配內(nèi)存函數(shù)指針 void (*free)(struct _swMemoryPool *pool, void *ptr); // 是否內(nèi)存函數(shù)指針 void (*destroy)(struct _swMemoryPool *pool); // 銷毀內(nèi)存函數(shù)指針 } swMemoryPool; typedef struct _swMemoryGlobal { uint8_t shared; uint32_t pagesize; // 指定每個swMemoryGlobal_page需要申請內(nèi)存大小 swLock lock; // 互斥鎖 swMemoryGlobal_page *root_page; // 指向第一個swMemoryGlobal_page指針,有頭指針可以銷毀內(nèi)存池 swMemoryGlobal_page *current_page; // 指向當前swMemoryGlobal_page指針 uint32_t current_offset; } swMemoryGlobal; typedef struct _swMemoryGlobal_page { struct _swMemoryGlobal_page *next; // 指向下一個節(jié)點 char memory[0]; // 這是一個柔性數(shù)組,用于記錄申請內(nèi)存后的內(nèi)存地址 } swMemoryGlobal_page;
這三者之間的關系如下:
swMemoryPool可以看做是一個類,它提過了alloc,free,destory方法,以及object屬性,object實際上是指向swMemoryGlobal的指針,而alloc,free,destory
則是對object操作,即通過alloc,free,destory操作swMemoryGlobal上的內(nèi)容,例如:
// src/core/base.c //init global shared memory SwooleG.memory_pool = swMemoryGlobal_new(SW_GLOBAL_MEMORY_PAGESIZE, 1); SwooleGS = SwooleG.memory_pool->alloc(SwooleG.memory_pool, sizeof(SwooleGS_t));
以上代碼是分配sizeof(SwooleGS_t)大小內(nèi)存
swMemoryGlobalswMemoryGlobal維護著一個鏈表,每個節(jié)點即swMemoryGlobal_page,root_page指向第一個節(jié)點,current_page指向當前節(jié)點,pagesize指為一個節(jié)點申請
內(nèi)存大小,current_offset則表示一個節(jié)點已被使用內(nèi)存
swoole根據(jù)swMemoryGlobal.pagesize申請指定大小的內(nèi)存,如下:
// src/memory/MemoryGlobal.c swMemoryGlobal_page *page = swMemoryGlobal_new_page(&gm);
上面說過swMemoryGlobal_page是一個鏈表節(jié)點,這里需要說明的是第一個節(jié)點,第一個節(jié)點的current_offset為sizeof(swMemoryGlobal) + sizeof(swMemoryPool);
而并非為0;如下代碼,當為第一個swMemoryGlobal_page申請內(nèi)存后,立馬就為swMemoryPool和swMemoryGlobal分配內(nèi)存
// src/memory/MemoryGlobal.c gm.pagesize = pagesize; // 系統(tǒng)申請一個pagesize大小內(nèi)存 swMemoryGlobal_page *page = swMemoryGlobal_new_page(&gm); if (page == NULL) { return NULL; } if (swMutex_create(&gm.lock, shared) < 0) { return NULL; } gm.root_page = page; // page->memory為空閑內(nèi)存 gm_ptr = (swMemoryGlobal *) page->memory; gm.current_offset += sizeof(swMemoryGlobal); // swMemoryPool指向空閑內(nèi)存偏移地址,占用sizeof(swMemoryPool)內(nèi)存 swMemoryPool *allocator = (swMemoryPool *) (page->memory + gm.current_offset); gm.current_offset += sizeof(swMemoryPool); allocator->object = gm_ptr; allocator->alloc = swMemoryGlobal_alloc; allocator->destroy = swMemoryGlobal_destroy; allocator->free = swMemoryGlobal_free; // 將gm寫入到gm_ptr,即空閑內(nèi)存前sizeof(gm)用于swMemoryGlobal memcpy(gm_ptr, &gm, sizeof(gm));分配內(nèi)存
分配內(nèi)存由swMemoryGlobal_alloc方法執(zhí)行;該方法為swMemoryPool一個函數(shù)指針,如下
allocator->alloc = swMemoryGlobal_alloc; // 分配方法
// src/core/base.c //init global shared memory SwooleG.memory_pool = swMemoryGlobal_new(SW_GLOBAL_MEMORY_PAGESIZE, 1); SwooleGS = SwooleG.memory_pool->alloc(SwooleG.memory_pool, sizeof(SwooleGS_t)); // src/memory/MemoryGlobal.c static void *swMemoryGlobal_alloc(swMemoryPool *pool, uint32_t size) { swMemoryGlobal *gm = pool->object; gm->lock.lock(&gm->lock); if (size > gm->pagesize - sizeof(swMemoryGlobal_page)) // sizeof(swMemoryGlobal_page)為swMemoryGlobal_page類型的指針大小 { swWarn("failed to alloc %d bytes, exceed the maximum size[%d].", size, gm->pagesize - (int) sizeof(swMemoryGlobal_page)); gm->lock.unlock(&gm->lock); return NULL; } // 如果一個節(jié)點不夠分配內(nèi)存,則重新申請一個新節(jié)點,并設置當前節(jié)點current_page為新節(jié)點 if (gm->current_offset + size > gm->pagesize - sizeof(swMemoryGlobal_page)) { swMemoryGlobal_page *page = swMemoryGlobal_new_page(gm); if (page == NULL) { swWarn("swMemoryGlobal_alloc alloc memory error."); gm->lock.unlock(&gm->lock); return NULL; } gm->current_page = page; } void *mem = gm->current_page->memory + gm->current_offset; gm->current_offset += size; gm->lock.unlock(&gm->lock); // 結果返回空閑內(nèi)存的偏移地址 return mem; }柔性數(shù)組
柔性數(shù)組(0長度數(shù)組)作用: 為了滿足需要變長度的結構體(結構體是可變長的)
數(shù)組名不占用空間,分配的內(nèi)存是連續(xù)的
不會像定長數(shù)組一樣浪費空間
不會像指針一樣需要分別分配內(nèi)存,分別釋放內(nèi)存
定長數(shù)組使用方便, 但是卻浪費空間, 指針形式只多使用了一個指針的空間, 不會造成
我的筆記
柔性數(shù)組參考
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/29521.html
摘要:前言中為了更好的進行內(nèi)存管理,減少頻繁分配釋放內(nèi)存空間造成的損耗和內(nèi)存碎片,程序設計并實現(xiàn)了三種不同功能的內(nèi)存池,和。比較特殊的是單鏈表內(nèi)存池的內(nèi)存只能增加不會減少。 前言 Swoole 中為了更好的進行內(nèi)存管理,減少頻繁分配釋放內(nèi)存空間造成的損耗和內(nèi)存碎片,程序設計并實現(xiàn)了三種不同功能的內(nèi)存池:FixedPool,RingBuffer 和 MemoryGlobal。 其中 Memor...
摘要:如果互斥鎖的持有者死亡了,或者持有這樣的互斥鎖的進程了互斥鎖所在的共享內(nèi)存或者持有這樣的互斥鎖的進程執(zhí)行了調(diào)用,則會解除鎖定該互斥鎖?;コ怄i的下一個持有者將獲取該互斥鎖并返回錯誤。 前言 swoole_table 一個基于共享內(nèi)存和鎖實現(xiàn)的超高性能,并發(fā)數(shù)據(jù)結構。用于解決多進程/多線程數(shù)據(jù)共享和同步加鎖問題。 swoole_table 的數(shù)據(jù)結構 swoole_table 實際上...
摘要:一個基于協(xié)議,開發(fā)的數(shù)據(jù)庫連接池。也可以通過其自身的管理機制來監(jiān)視數(shù)據(jù)庫連接的數(shù)量使用情況等。超出最大連接數(shù)會采用協(xié)程掛起,等到有連接關閉再恢復協(xié)程繼續(xù)操作。 SMProxy GITHUB:https://github.com/louislivi/... Swoole MySQL Proxy 一個基于 MySQL 協(xié)議,Swoole 開發(fā)的MySQL數(shù)據(jù)庫連接池。 原理 將數(shù)據(jù)庫連接作...
摘要:是緩存區(qū)高水位線,達到了說明緩沖區(qū)即將滿了創(chuàng)建線程函數(shù)用于將監(jiān)控的存放于中向中添加監(jiān)聽的文件描述符等待所有的線程開啟事件循環(huán)利用創(chuàng)建線程,線程啟動函數(shù)是保存監(jiān)聽本函數(shù)將用于監(jiān)聽的存放到當中,并設置相應的屬性 Server 的啟動 在 server 啟動之前,swoole 首先要調(diào)用 php_swoole_register_callback 將 PHP 的回調(diào)函數(shù)注冊到 server...
閱讀 808·2021-09-06 15:02
閱讀 2451·2019-08-30 15:43
閱讀 2175·2019-08-30 11:26
閱讀 2381·2019-08-26 12:12
閱讀 3548·2019-08-23 18:24
閱讀 3267·2019-08-23 18:16
閱讀 704·2019-08-23 17:02
閱讀 2252·2019-08-23 15:34