在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

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

3天內不再提示

malloc和內存池技術的區別 內存池技術性能優化方案

電子設計 ? 來源:面包板社區 ? 作者:一口Linux ? 2021-03-02 15:29 ? 次閱讀

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

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

原來技術也有大眾貨以及定制品。

通用 VS 定制

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

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

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

如果malloc找不到一塊合適的空閑內存,那么調用brk等系統調用擴大堆區從而獲得更多的空閑內存

malloc調用brk后開始轉入內核態,此時操作系統中的虛擬內存系統開始工作,擴大進程的堆區,注意額外擴大的這一部分內存僅僅是虛擬內存,操作系統并沒有為此分配真正的物理內存

brk執行結束后返回到malloc,從內核態切換到用戶態,malloc找到一塊合適的空閑內存后返回

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

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

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

那么內存池技術是怎樣優化性能的呢?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

編輯:hfy

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內存
    +關注

    關注

    8

    文章

    3115

    瀏覽量

    75072
  • 局部存儲
    +關注

    關注

    0

    文章

    2

    瀏覽量

    5488
  • malloc
    +關注

    關注

    0

    文章

    53

    瀏覽量

    204
收藏 人收藏

    評論

    相關推薦
    熱點推薦

    HarmonyOS優化應用內存占用問題性能優化

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

    HarmonyOS優化應用內存占用問題性能優化

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

    TECS OpenStack資源虛機殘留導致網元異常的問題處理

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

    hyper 內存,Hyper內存:如何監控與優化hyper-v虛擬機的內存使用

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

    DDR5內存與DDR4內存性能差異

    DDR5內存與DDR4內存性能差異 隨著技術的發展,內存技術也在不斷進步。DDR5
    的頭像 發表于 11-29 14:58 ?2060次閱讀

    如何選擇DDR內存條 DDR3與DDR4內存區別

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

    HBM與GDDR內存技術全解析

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

    如何優化RAM內存使用

    優化RAM內存使用是一個重要的任務,特別是對于那些擁有有限內存資源的用戶。以下是一些優化RAM內存使用的策略,這些策略可以幫助您更有效地使用
    的頭像 發表于 11-11 09:58 ?1308次閱讀

    污水處理預沉物聯網系統解決方案

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

    離心溫度監測物聯網系統方案

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

    什么是內存通道技術

    內存通道技術作為計算機系統中的核心組成部分,對于提升數據處理能力、優化系統性能以及增強系統的穩定性與擴展性等方面發揮著至關重要的作用。以下是對內存
    的頭像 發表于 09-04 12:47 ?1487次閱讀

    買藥秒送 JADE動態線程實踐及原理淺析

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

    buffers內存與cached內存區別

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

    內存的種類都有哪些?有什么區別

    內存,作為計算機中不可或缺的組成部分,承擔著存儲和交換數據的重要任務。隨著技術的不斷發展,內存的種類也日益豐富,每種類型都有其獨特的特點和適用場景。以下是對內存種類及其
    的頭像 發表于 07-15 18:15 ?1.5w次閱讀

    使用rt_malloc申請內存空間失敗,顯示沒有內存怎么解決?

    + net_server + crclib) 的情況下,還有2個堆棧空間2048的應用線程,使用rt_malloc申請內存空間失敗,顯示沒有內存。經測試,只能申請1200bytes 以下的
    發表于 07-04 08:10
    主站蜘蛛池模板: 亚洲精品美女久久久久网站 | 丁香六月婷婷精品免费观看 | 34pao强力打造免费永久视频 | 5151hh四虎国产精品 | 四虎成人精品在永久在线观看 | 欧美另类自拍 | 国产人成精品香港三级古代 | 国产人人爱 | 亚洲免费毛片 | 欧美成人午夜 | 88av免费观看 | 四虎在线观看一区二区 | 无遮挡高清一级毛片免费 | 色麒麟影院 | 成人毛片在线播放 | 中文字幕在线一区 | 亚洲啪啪看看 | 欧美精品色精品一区二区三区 | 亚洲精品成人久久久影院 | 四虎www成人影院观看 | 精品国产乱码一区二区三区 | 成人亚洲欧美在线电影www色 | 亚洲区中文字幕 | 一级做a爱片特黄在线观看免费看 | 国产精品视频第一区二区三区 | 日本加勒比在线视频 | 日本成人免费在线视频 | 人与性www | 欧美黄色免费看 | 男女性生动态免费视频 | 国产精品视频一区二区三区 | 扛着高跟鞋丝袜腿呻吟视频 | 国产a一级毛片午夜剧场14 | 亚洲一区二区三区深夜天堂 | 大杳蕉伊人狼人久久一本线 | 久久综合图片 | 7799国产精品久久久久99 | 大色综合 | 四虎国产精品免费视 | 狠狠乱| 国产91小视频在线观看 |