一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

malloc和內(nèi)存池技術(shù)的區(qū)別 內(nèi)存池技術(shù)性能優(yōu)化方案

電子設(shè)計 ? 來源:面包板社區(qū) ? 作者:一口Linux ? 2021-03-02 15:29 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

大家生活中肯定都有這樣的經(jīng)驗,那就是大眾化的產(chǎn)品都比較便宜,但便宜的大眾產(chǎn)品就是一個詞,普通;而可以定制的產(chǎn)品一般都價位不凡,這種定制的產(chǎn)品注定不會在大眾中普及,因此定制產(chǎn)品就是一個詞,獨特。

有的同學(xué)可能會有疑問,你不是要聊技術(shù)嗎?怎么又說起消費了?

原來技術(shù)也有大眾貨以及定制品。

通用 VS 定制

作為程序員(C/C++)我們知道申請內(nèi)存使用的是malloc,malloc其實就是一個通用的大眾貨,什么場景下都可以用,但是什么場景下都可以用就意味著什么場景下都不會有很高的性能。

malloc性能不高的原因一在于其沒有為特定場景做優(yōu)化,除此之外還在于malloc看似簡單,但是其調(diào)用過程是很復(fù)雜的,一次malloc的調(diào)用過程可能需要經(jīng)過操作系統(tǒng)的配合才能完成。 那么調(diào)用malloc時底層都發(fā)生了什么呢?簡單來說會有這樣典型的幾個步驟:

malloc開始搜索空閑內(nèi)存塊,如果能找到一塊大小合適的就分配出去

如果malloc找不到一塊合適的空閑內(nèi)存,那么調(diào)用brk等系統(tǒng)調(diào)用擴大堆區(qū)從而獲得更多的空閑內(nèi)存

malloc調(diào)用brk后開始轉(zhuǎn)入內(nèi)核態(tài),此時操作系統(tǒng)中的虛擬內(nèi)存系統(tǒng)開始工作,擴大進程的堆區(qū),注意額外擴大的這一部分內(nèi)存僅僅是虛擬內(nèi)存,操作系統(tǒng)并沒有為此分配真正的物理內(nèi)存

brk執(zhí)行結(jié)束后返回到malloc,從內(nèi)核態(tài)切換到用戶態(tài),malloc找到一塊合適的空閑內(nèi)存后返回

以上就是一次內(nèi)存申請的完整過程,我們可以看到,一次內(nèi)存申請過程其實是非常復(fù)雜的,關(guān)于這個問題的詳細討論你可以參考這里。 既然每次分配內(nèi)存都要經(jīng)過這么復(fù)雜的過程,那么如果程序大量使用malloc申請內(nèi)存那么該程序注定無法獲得高性能。 幸好,除了大眾貨的malloc,我們還可以私人定制,也就是針對特定場景自己來維護內(nèi)存申請和分配,這就是高性能高并發(fā)必備的內(nèi)存池技術(shù)。

內(nèi)存池技術(shù)有什么特殊的嗎? 有的同學(xué)可能會說,等等,那malloc和這里提到的內(nèi)存池技術(shù)有什么區(qū)別呢? 第一個區(qū)別在于我們所說的malloc其實是標準庫的一部分,位于標準庫這一層;而內(nèi)存池是應(yīng)用程序的一部分。

其次在于定位,我們自己實現(xiàn)的malloc其實也是定位通用性的,通用性的內(nèi)存分配器設(shè)計實現(xiàn)往往比較復(fù)雜,但是內(nèi)存池技術(shù)就不一樣了,內(nèi)存池技術(shù)專用于某個特定場景,以此優(yōu)化程序性能,但內(nèi)存池技術(shù)的通用性是很差的,在一種場景下有很高性能的內(nèi)存池基本上沒有辦法在其它場景也能獲得高性能,甚至根本就不能用于其它場景,這就是內(nèi)存池這種技術(shù)的定位。

那么內(nèi)存池技術(shù)是怎樣優(yōu)化性能的呢?

內(nèi)存池技術(shù)原理 簡單來說,內(nèi)存池技術(shù)一次性獲取到大塊內(nèi)存,然后在其之上自己管理內(nèi)存的申請和釋放,這樣就繞過了標準庫以及操作系統(tǒng):

也就是說,通過內(nèi)存池,一次內(nèi)存的申請再也不用去繞一大圈了。 除此之外,我們可以根據(jù)特定的使用模式來進一步優(yōu)化,比如在服務(wù)器端,每次用戶請求需要創(chuàng)建的對象可能就那幾種,那么這時我們就可以在自己的內(nèi)存池上提前創(chuàng)建出這些對象,當業(yè)務(wù)邏輯需要時就從內(nèi)存池中申請已經(jīng)創(chuàng)建好的對象,使用完畢后還回內(nèi)存池。 因此我們可以看到,這種為某些應(yīng)用場景定制的內(nèi)存池相比通用的比如malloc內(nèi)存分配器會有大的優(yōu)勢。 接下來我們就著手實現(xiàn)一個。

實現(xiàn)內(nèi)存池的考慮 值得注意的是,內(nèi)存池實際上有很多的實現(xiàn)方法,在這里我們還是以服務(wù)器端編程為例來說明。 假設(shè)你的服務(wù)器程序非常簡單,處理用戶請求時只使用一種對象(數(shù)據(jù)結(jié)構(gòu)),那么最簡單的就是我們提前申請出一堆來,使用的時候拿出一個,使用完后還回去:

怎么樣,足夠簡單吧!這樣的內(nèi)存池只能分配特定對象(數(shù)據(jù)結(jié)構(gòu)),當然這樣的內(nèi)存池需要自己維護哪些對象是已經(jīng)被分配出去的,哪些是還沒有被使用的。 但是,在這里我們可以實現(xiàn)一個稍微復(fù)雜一些的,那就是可以申請不同大小的內(nèi)存,而且由于是服務(wù)器端編程,那么一次用戶請求過程中我們只申請內(nèi)存,只有當用戶請求處理完畢后一次性釋放所有內(nèi)存,從而將內(nèi)存申請釋放的開銷降低到最小。 因此,你可以看到,內(nèi)存池的設(shè)計都是針對特定場景的。 現(xiàn)在,有了初步的設(shè)計,接下來就是細節(jié)了。

數(shù)據(jù)結(jié)構(gòu) 為了能夠分配大小可變的對象,顯然我們需要管理空閑內(nèi)存塊,我們可以用一個鏈表把所有內(nèi)存塊鏈接起來,然后使用一個指針來記錄當前空閑內(nèi)存塊的位置,如圖所示:

從圖中我們可以看到,有兩個空閑內(nèi)存塊,空閑內(nèi)存之間使用鏈表鏈接起來,每個內(nèi)存塊都是前一個的2倍,也就是說,當內(nèi)存池中的空閑內(nèi)存不足以分配時我們就向malloc申請內(nèi)存,只不過其大小是前一個的2倍:

其次,我們有一個指針free_ptr,指向接下來的空閑內(nèi)存塊起始位置,當向內(nèi)存池分配內(nèi)存時找到free_ptr并判斷當前內(nèi)存池剩余空閑是否足夠就可以了,有就分配出去并修改free_ptr,否則向malloc再次成倍申請內(nèi)存。 從這里的設(shè)計可以看出,我們的內(nèi)存池其實是不會提供類似free這樣的內(nèi)存釋放函數(shù)的,如果要釋放內(nèi)存,那么會一次性將整個內(nèi)存池釋放掉,這一點和通用的內(nèi)存分配器是不一樣。 現(xiàn)在,我們可以分配內(nèi)存了,還有一個問題是所有內(nèi)存池設(shè)計不得不考慮的,那就是線程安全,這個話題你可以參考這里。

線程安全 顯然,內(nèi)存池不應(yīng)該局限在單線程場景,那我們的內(nèi)存池要怎樣實現(xiàn)線程安全呢? 有的同學(xué)可能會說這還不簡單,直接給內(nèi)存池一把鎖保護就可以了。

這種方法是不是可行呢?還是那句話,It depends,要看情況。 如果你的程序有大量線程申請釋放內(nèi)存,那么這種方案下鎖的競爭將會非常激烈,線程這樣的場景下使用該方案不會有很好的性能。 那么還有沒有一種更好的辦法嗎?答案是肯定的。

線程局部存儲 既然多線程使用線程池存在競爭問題,那么干脆我們?yōu)槊總€線程維護一個內(nèi)存池就好了,這樣多線程間就不存在競爭問題了。 那么我們該怎樣為每個線程維護一個內(nèi)存池呢? 線程局部存儲,Thread Local Storage正是用于解決這一類問題的,什么是線程局部存儲呢? 簡單說就是,我們可以創(chuàng)建一個全局變量,因此所有線程都可以使用該全局變量,但與此同時,我們將該全局變量聲明為線程私有存儲,那么這時雖然所有線程依然看似使用同一個全局變量,但該全局變量在每個線程中都有自己的副本,變量指向的值是線程私有的,相互之間不會干擾。

關(guān)于線程局部存儲,可以參考這里。 假設(shè)這個全局變量是一個整數(shù),變量名字為global_value,初始值為100,那么當線程A將global_value修改為200時,線程B看到的global_value的值依然為100,只有線程A看到的global_value為200,這就是線程局部存儲的作用。

線程局部存儲+內(nèi)存池 有了線程局部存儲問題就簡單了,我們可以將內(nèi)存池聲明為線程局部存儲,這樣每個線程都只會操作屬于自己的內(nèi)存池,這樣就再也不會有鎖競爭問題了。

注意,雖然這里給出了線程局部存儲的設(shè)計,但并不是說加鎖的方案就比不上線程局部存儲方案,還是那句話,一切要看使用場景,如果加鎖的方案夠用,那么我們就沒有必要絞盡腦汁的去用其它方案,因為加鎖的方案更簡單,代碼也更容易維護。 還需要提醒的是,這里只是給出了內(nèi)存池的一種實現(xiàn)方法,并不是說所有內(nèi)存池都要這么設(shè)計,內(nèi)存池可以簡單也可復(fù)雜,一切要看實際場景,這一點也需要注意。

其它內(nèi)存池形式 到目前為止我們給出了兩種內(nèi)存池的設(shè)計方法,第一種是提前創(chuàng)建出一堆需要的對象(數(shù)據(jù)結(jié)構(gòu)),自己維護好哪些對象(數(shù)據(jù)結(jié)構(gòu))可用哪些已被分配;第二種可以申請任意大小的內(nèi)存空間,使用過程中只申請不釋放,最后一次性釋放。這兩種內(nèi)存池天然適用于服務(wù)器端編程。 最后我們再來介紹一種內(nèi)存池實現(xiàn)技術(shù),這種內(nèi)存池會提前申請出一大段內(nèi)存,然后將這一大段內(nèi)存切分為大小相同的小內(nèi)存塊:

然后我們自己來維護這些被切分出來的小內(nèi)存塊哪些是空閑的哪些是已經(jīng)被分配的,比如我們可以使用棧這種數(shù)據(jù)結(jié)構(gòu),最初把所有空閑內(nèi)存塊地址push到棧中,分配內(nèi)存是就pop出來一個,用戶使用完畢后再push回棧里。

從這里的設(shè)計我們可以看出,這種內(nèi)存池有一個限制,這個限制就是說程序申請的最大內(nèi)存不能超過這里內(nèi)存塊的大小,否則不足以裝下用戶數(shù)據(jù),這需要我們對程序所涉及的業(yè)務(wù)非常了解才可以。 用戶申請到內(nèi)存后根據(jù)需要將其塑造成特定對象(數(shù)據(jù)結(jié)構(gòu))。 關(guān)于線程安全的問題,可以同樣采用線程局部存儲的方式來實現(xiàn):

一個有趣的問題 除了線程安全,這里還有一個非常有趣的問題,那就是如果線程A申請的對象被線程B拿去釋放,我們的內(nèi)存池該怎么處理呢? 這個問題之所以有趣是因為我們必須知道該內(nèi)存屬于哪個線程的局部存儲,但申請的內(nèi)存本身并不能告訴你這樣的信息。 有的同學(xué)可能會說這還不簡單,不就是一個指針到另一個指針的映射嗎,直接用map之類存起來就好了,但問題并沒有這么簡單,原因就在于如果我們切分的內(nèi)存塊很小,那么會存在大量內(nèi)存塊,這就需要存儲大量的映射關(guān)系,有沒有辦法改進呢? 改進方法是這樣的,一般來說,我們申請到的大段內(nèi)存其實是會按照特定大小進行內(nèi)存對齊,我們假設(shè)總是按照4K字節(jié)對齊,那么該大段內(nèi)存的起始地址后12個bit(4K = 2^12)為總是0,比如地址0x9abcd000,同時我們也假設(shè)申請到的大段內(nèi)存大小也是4K:

那么我們就能知道該大段內(nèi)存中的各個小內(nèi)存塊起始地址除了后12個bit位外都是一樣的:

這樣拿到任意一個內(nèi)存的地址我們就能知道對應(yīng)的大段內(nèi)存的起始地址,只需要簡單的將后12個bit置為0即可,有了大段內(nèi)存的起始地址剩下的就簡單了,我們可以在大段內(nèi)存中的最后保存對應(yīng)的線程局部存儲信息:

這樣我們對任意一個內(nèi)存塊地址進行簡單的位運算就可以得到對應(yīng)的線程局部存儲信息,大大減少了維護映射信息對內(nèi)存的占用。

總結(jié) 內(nèi)存池是高性能服務(wù)器中常見的一種優(yōu)化技術(shù),在這里我們介紹了三種實現(xiàn)方法,值得注意的是,內(nèi)存池實現(xiàn)沒有統(tǒng)一標準,一切都要根據(jù)具體場景定制,因此我們可以看到內(nèi)存池設(shè)計是有針對性的,當然其反面就是不具備通用性。

編輯:hfy

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 內(nèi)存
    +關(guān)注

    關(guān)注

    8

    文章

    3125

    瀏覽量

    75270
  • 局部存儲
    +關(guān)注

    關(guān)注

    0

    文章

    2

    瀏覽量

    5494
  • malloc
    +關(guān)注

    關(guān)注

    0

    文章

    53

    瀏覽量

    226
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    HarmonyOS優(yōu)化應(yīng)用內(nèi)存占用問題性能優(yōu)化

    ,不同系統(tǒng)的閾值不同)時,系統(tǒng)可能會認為應(yīng)用存在嚴重的內(nèi)存問題,并可能會強制殺死該應(yīng)用進程,以保證設(shè)備系統(tǒng)的穩(wěn)定性和性能。為了避免應(yīng)用被系統(tǒng)殺死,開發(fā)者可以考慮以下兩點: 優(yōu)化資源使用:通過合理設(shè)置圖片
    發(fā)表于 05-24 17:20

    HarmonyOS優(yōu)化應(yīng)用內(nèi)存占用問題性能優(yōu)化

    應(yīng)用開發(fā)過程中注重內(nèi)存管理,積極采取措施來減少內(nèi)存占用,以優(yōu)化應(yīng)用程序的性能和用戶體驗。 HarmonyOS提供了一些內(nèi)存管理的工具和接口,
    發(fā)表于 05-21 11:27

    TECS OpenStack資源虛機殘留導(dǎo)致網(wǎng)元異常的問題處理

    某運營商TECS資源的一臺主機內(nèi)存故障,進行關(guān)機、內(nèi)存更換操作,虛機自動遷移到其他主機上,同時做了其他虛擬機的手動遷移操作。后續(xù)在TECS上出現(xiàn)虛機內(nèi)核異常告警,如下圖所示。
    的頭像 發(fā)表于 03-03 09:42 ?384次閱讀
    TECS OpenStack資源<b class='flag-5'>池</b>虛機殘留導(dǎo)致網(wǎng)元異常的問題處理

    hyper 內(nèi)存,Hyper內(nèi)存:如何監(jiān)控與優(yōu)化hyper-v虛擬機的內(nèi)存使用

    :如何監(jiān)控與優(yōu)化hyper-v虛擬機的內(nèi)存使用。 ? ?在虛擬化環(huán)境中,合理監(jiān)控和優(yōu)化Hyper-V虛擬機的內(nèi)存使用對于提升性能和資源利用率
    的頭像 發(fā)表于 01-24 14:15 ?1115次閱讀
    hyper <b class='flag-5'>內(nèi)存</b>,Hyper<b class='flag-5'>內(nèi)存</b>:如何監(jiān)控與<b class='flag-5'>優(yōu)化</b>hyper-v虛擬機的<b class='flag-5'>內(nèi)存</b>使用

    虛擬內(nèi)存對計算機性能的影響

    在現(xiàn)代計算機系統(tǒng)中,內(nèi)存管理是確保系統(tǒng)高效運行的關(guān)鍵因素之一。虛擬內(nèi)存技術(shù)作為內(nèi)存管理的核心組成部分,對于提升計算機性能和用戶體驗起著至關(guān)重
    的頭像 發(fā)表于 12-04 09:17 ?3484次閱讀

    虛擬內(nèi)存不足如何解決 虛擬內(nèi)存和物理內(nèi)存區(qū)別

    虛擬內(nèi)存不足的解決方案 虛擬內(nèi)存不足是計算機用戶經(jīng)常遇到的問題,尤其是在運行大型軟件或多任務(wù)處理時。以下是一些解決虛擬內(nèi)存不足問題的方法: 增加物理
    的頭像 發(fā)表于 12-04 09:14 ?1481次閱讀

    DDR5內(nèi)存與DDR4內(nèi)存性能差異

    DDR5內(nèi)存與DDR4內(nèi)存性能差異 隨著技術(shù)的發(fā)展,內(nèi)存技術(shù)也在不斷進步。DDR5
    的頭像 發(fā)表于 11-29 14:58 ?2329次閱讀

    如何選擇DDR內(nèi)存條 DDR3與DDR4內(nèi)存區(qū)別

    隨著技術(shù)的不斷進步,計算機內(nèi)存技術(shù)也在不斷發(fā)展。DDR(Double Data Rate)內(nèi)存條作為計算機的重要組成部分,其性能直接影響到電
    的頭像 發(fā)表于 11-20 14:24 ?6129次閱讀

    HBM與GDDR內(nèi)存技術(shù)全解析

    在高性能圖形處理領(lǐng)域,內(nèi)存技術(shù)起著至關(guān)重要的作用。本文介紹兩種主要的圖形內(nèi)存技術(shù):高帶寬內(nèi)存(H
    的頭像 發(fā)表于 11-15 10:47 ?3241次閱讀
    HBM與GDDR<b class='flag-5'>內(nèi)存</b><b class='flag-5'>技術(shù)</b>全解析

    如何優(yōu)化RAM內(nèi)存使用

    優(yōu)化RAM內(nèi)存使用是一個重要的任務(wù),特別是對于那些擁有有限內(nèi)存資源的用戶。以下是一些優(yōu)化RAM內(nèi)存使用的策略,這些策略可以幫助您更有效地使用
    的頭像 發(fā)表于 11-11 09:58 ?1448次閱讀

    污水處理預(yù)沉物聯(lián)網(wǎng)系統(tǒng)解決方案

    ,成為了當前水務(wù)行業(yè)的重要發(fā)展方向。 系統(tǒng)概述 對此,物通博聯(lián)提供基于工業(yè)智能網(wǎng)關(guān)的污水處理預(yù)沉物聯(lián)網(wǎng)系統(tǒng)解決方案,是基于物聯(lián)網(wǎng)技術(shù),結(jié)合傳感器、PLC(可編程邏輯控制器)、無線通信等技術(shù)
    的頭像 發(fā)表于 10-09 10:39 ?544次閱讀
    污水處理預(yù)沉<b class='flag-5'>池</b>物聯(lián)網(wǎng)系統(tǒng)解決<b class='flag-5'>方案</b>

    離心溫度監(jiān)測物聯(lián)網(wǎng)系統(tǒng)方案

    在現(xiàn)有技術(shù)的鋼丸生產(chǎn)工藝中,一般采用離心法實現(xiàn)鋼丸的成形,其原理是將熔融狀態(tài)的鋼水裝入離心機中,通過離心力將鋼水甩出離心機,離心機位于一個冷卻的中部,因此從離心機中甩出的鋼水落入冷卻池內(nèi)的冷卻
    的頭像 發(fā)表于 09-20 10:56 ?366次閱讀
    離心<b class='flag-5'>池</b>溫度監(jiān)測物聯(lián)網(wǎng)系統(tǒng)<b class='flag-5'>方案</b>

    什么是內(nèi)存通道技術(shù)

    內(nèi)存通道技術(shù)作為計算機系統(tǒng)中的核心組成部分,對于提升數(shù)據(jù)處理能力、優(yōu)化系統(tǒng)性能以及增強系統(tǒng)的穩(wěn)定性與擴展性等方面發(fā)揮著至關(guān)重要的作用。以下是對內(nèi)存
    的頭像 發(fā)表于 09-04 12:47 ?1609次閱讀

    買藥秒送 JADE動態(tài)線程實踐及原理淺析

    一、背景及JADE介紹 買藥秒送是健康即時零售業(yè)務(wù)新的核心流量場域,面對京東首頁高流量曝光,我們對頻道頁整個技術(shù)架構(gòu)方案進行升級,保障接口高性能、系統(tǒng)高可用。 動態(tài)線程是買藥頻道應(yīng)用
    的頭像 發(fā)表于 09-04 11:11 ?1182次閱讀
    買藥秒送 JADE動態(tài)線程<b class='flag-5'>池</b>實踐及原理淺析

    buffers內(nèi)存與cached內(nèi)存區(qū)別

    free 命令是Linux系統(tǒng)上查看內(nèi)存使用狀況最常用的工具,然而很少有人能說清楚 “buffers” 與 “cached” 之間的區(qū)別。
    的頭像 發(fā)表于 07-29 14:17 ?799次閱讀
    buffers<b class='flag-5'>內(nèi)存</b>與cached<b class='flag-5'>內(nèi)存</b>的<b class='flag-5'>區(qū)別</b>